Merge branch 'develop' into feature/Digital/SSR-139

This commit is contained in:
Jeremy Zimmerman 2022-12-06 10:40:32 -05:00
commit a8a1c849e3
10 changed files with 3438 additions and 27 deletions

View file

@ -0,0 +1,398 @@
// 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 { useMainStore } 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(),
}));
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,
},
],
},
],
};
};
useMainStore().pageData = baseStoreGettersPageData;
useMainStore().damage = baseStoreGettersDamage;
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({});
useMainStore().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
useMainStore().pageData = jest.fn(() => {
return {
partsOrQuestions: [],
};
});
useMainStore().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
useMainStore().pageData = baseStoreGettersPageData;
useMainStore().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.getParts = 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 pinia store", async () => {
// Arrange
const { wrapper } = setupMocks({});
wrapper.vm.questionsData = [
{
glassLocation: "Windshield",
glassName: "Single",
answerData: {
answerResult: "FW04848",
answeredQuestions: [],
},
},
];
useMainStore().getParts = jest.fn(() => {
return {
data: {
glassPieceParts: [],
},
};
});
// Act
wrapper.vm.forwardButtonAction();
await nextTick();
//Assert
expect(wrapper.vm.savePartQuestionAnswers).toHaveBeenCalled;
wrapper.unmount();
});
test("Should call GET_PARTS API", async () => {
// Arrange
const { wrapper } = setupMocks({});
wrapper.vm.questionsData = [
{
glassLocation: "Windshield",
glassName: "Single",
answerData: {
answerResult: "FW04848",
answeredQuestions: [],
},
},
];
useMainStore().getParts = jest.fn(() => {
return {
data: {
glassPieceParts: [],
},
};
});
// Act
wrapper.vm.forwardButtonAction();
await nextTick();
//Assert
expect(wrapper.vm.getParts).toHaveBeenCalled;
wrapper.unmount();
});
test("Should trigger navigateForward", async () => {
// Arrange
const { wrapper } = setupMocks({});
wrapper.vm.questionsData = [
{
glassLocation: "Windshield",
glassName: "Single",
answerData: {
answerResult: "FW04848",
answeredQuestions: [],
},
},
];
useMainStore().getParts = 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: "savePartQuestionAnswers",
data: {},
},
{
actionName: "getParts",
data: {},
},
],
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;
},
},
},
}) {
useMainStore().getParts = jest.fn(() => {
return {
data: {
glassPieceParts: [],
},
};
});
const mountOptions = getMountOptions({
...mountOptionsMockData,
mixins: [baseMixin, vehicleQuestionsMixin],
});
mountOptions["attachTo"] = document.body;
const wrapper = shallowMount(partQuestions, mountOptions);
return { wrapper };
}

View file

@ -20,7 +20,7 @@
name: "make-question",
data() {
return {
makes: Array,
makes: [],
};
},
props: {

View file

@ -5,9 +5,8 @@
<div class="select-car-form rounded text-center">
<vehicleBanner cmsWidgetName="VehicleBannerWidget" :displayGenericVehicleImage="true"/>
<siteSubHeader
cmsWidgetName="SiteSubHeaderWidget"
cmsWidgetName="SiteSubHeaderWidget"
:hasBackButton="true"
:backButtonAccessibleText="backButtonAccessibleText"
@click-event="backButtonAction"
/>
<div class="fade-on-route-transition">
@ -97,12 +96,6 @@
this.$route
);
},
},
computed: {
backButtonAccessibleText()
{
return this.getCmsContent(this.cmsWidgetName, "BackButtonAccessibleText")
},
},
}
};
</script>

View file

@ -0,0 +1,425 @@
// Components
import vehicleParts from "@/layouts/vehicle-parts/vehicle-parts.vue";
import glassPartQuestion from "@/layouts/vehicle-parts/glass-part-question/glass-part-question";
// Supporting Files
import { settleAllPromises } from "@/helpers/layout-helper.js";
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
import { shallowMount } from "@vue/test-utils";
import { getMountOptions } from "@/helpers/unit-test-helper.js";
import { nextTick } from "vue";
import baseMixin from "@/mixins/base-mixin.js";
import { useMainStore } from "@/store";
import { navigationScenarios } from "@/router/router-constants/navigation-scenarios";
// 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(),
}));
useMainStore().getters = {
pageData: jest.fn(),
damage: {
isRepair: false,
},
};
const basePartResponse = {
partsOrQuestions: [
{
glassName: "Stationary",
glassLocation: "Rear",
parts: [
{
partNumber: "DB12209GTYN",
description: "heated glass, solar, 1 hole",
color: "Green Tint",
requiresRecalibration: false,
requiresCapabilityQuestions: false,
childParts: null,
},
{
partNumber: "DB12209YPYNOEM",
description: "heated glass, solar, 1 hole",
color: "Gray Tint Privacy",
requiresRecalibration: false,
requiresCapabilityQuestions: false,
childParts: null,
},
],
partQuestions: null,
},
],
};
describe("vehicle-parts.vue", () => {
test("Set cms content called on load", async () => {
//Arrange
useMainStore().pageData = jest.fn();
useMainStore().pageData.mockReturnValue(basePartResponse);
useMainStore().lineItems = { glassParts: null };
const { wrapper, apiPromise } = setupMocks({
mountOptionsMockData: {
router: {
navigate: jest.fn()
},
route: {
query: {
issPage: "vehicle-parts",
},
},
useMainStore: {
getters: useMainStore().getters,
},
},
});
//Act
vehicleParts.beforeRouteEnter.call(
wrapper.vm,
{ query: { issPage: "vehicle-parts" } },
undefined,
(c) => c(wrapper.vm)
);
wrapper.vm.setCmsContent = jest.fn();
//Assert
apiPromise.finally(() => {
expect(wrapper.vm.setCmsContent).toHaveBeenCalled();
});
});
test("PageData / isRepair populated in Vuex. arePagePrerequisitesValid should be true ", async () => {
//Arrange
useMainStore().pageData = jest.fn();
useMainStore().pageData.mockReturnValue(basePartResponse);
useMainStore().lineItems = { glassParts: null };
useMainStore().damage.isRepair = false;
const { wrapper } = setupMocks({
mountOptionsMockData: {
router: {
navigate: jest.fn(),
},
route: {
query: {
issPage: "vehicle-parts",
},
},
},
});
//Act
vehicleParts.beforeRouteEnter.call(
wrapper.vm,
{ query: { issPage: "vehicle-parts" } },
undefined,
(c) => c(wrapper.vm)
);
let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid();
await nextTick();
//Assert
expect(arePagePrerequisitesValid).toBe(true);
});
test("Initial data, should populate this.selectedGlassParts", async () => {
//Arrange
useMainStore().pageData = jest.fn();
useMainStore().pageData.mockReturnValue(basePartResponse);
useMainStore().lineItems = { glassParts: [{ partNumber: "DB12209YPYNOEM" }] };
const { wrapper } = setupMocks({
mountOptionsMockData: {
router: {
navigate: jest.fn(),
},
route: {
query: {
issPage: "vehicle-parts",
},
},
},
});
//Act
vehicleParts.beforeRouteEnter.call(
wrapper.vm,
{ query: { issPage: "vehicle-parts" } },
undefined,
(c) => c(wrapper.vm)
);
await nextTick();
//Assert
expect(wrapper.vm.selectedGlassParts).toEqual({
"Rear-Stationary": {
partNumber: "DB12209YPYNOEM",
description: "heated glass, solar, 1 hole",
color: "Gray Tint Privacy",
requiresRecalibration: false,
requiresCapabilityQuestions: false,
childParts: null,
},
});
});
test("User had part questions > navigateBack triggers a router.navigateWithoutSaving change with correct scenario", async () => {
//Arrange
const { wrapper } = setupMocks({
mountOptionsMockData: {
router: {
navigate: jest.fn(),
},
route: {
query: {
issPage: "vehicle-parts",
},
},
},
});
//Act
vehicleParts.beforeRouteEnter.call(
wrapper.vm,
{ query: { issPage: "vehicle-parts" } },
undefined,
(c) => c(wrapper.vm)
);
wrapper.vm.navigateBack();
//Assert
expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith(
navigationScenarios.CLICKED_BACK_WITH_NO_VIN_NOR_QUESTIONS,
wrapper.vm.$route
);
});
test("User did not have part questions > navigateBack triggers a router.navigate change with correct scenario", async () => {
//Arrange
const { wrapper } = setupMocks({
mountOptionsMockData: {
router: {
navigate: jest.fn(),
},
route: {
query: {
issPage: "vehicle-parts",
},
},
},
});
//Act
vehicleParts.beforeRouteEnter.call(
wrapper.vm,
{ query: { issPage: "vehicle-parts" } },
undefined,
(c) => c(wrapper.vm)
);
wrapper.vm.navigateBack();
//Assert
expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith(
navigationScenarios.CLICKED_BACK_WITH_NO_VIN_NOR_QUESTIONS,
wrapper.vm.$route
);
});
test("ForwardButtonAction triggers a router.navigate change if there are child part questions", async () => {
//Arrange
useMainStore().pageData = jest.fn();
useMainStore().pageData.mockReturnValue({
partsOrQuestions: [
{
glassName: "Single",
glassLocation: "Windshield",
parts: [
{
partNumber: "FW03861GTYN",
description:
"rain sensor, heated glass, auto dimming mirror, solar, 3rd visor band, condensation sensor",
color: "Green Tint",
requiresRecalibration: false,
requiresCapabilityQuestions: false,
recalibrationType: null,
childParts: null,
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,
},
],
},
],
},
],
partQuestions: null,
},
],
});
useMainStore().lineItems = { glassParts: {} };
const { wrapper } = setupMocks({
mountOptionsMockData: {
router: {
navigate: jest.fn(),
},
route: {
query: {
issPage: "vehicle-parts",
},
},
},
});
wrapper.setData({
selectedGlassParts: { "Rear-Stationary": { partNumber: "FW03861GTYN" } },
});
//Act
vehicleParts.beforeRouteEnter.call(
wrapper.vm,
{ query: { issPage: "vehicle-parts" } },
undefined,
(c) => c(wrapper.vm)
);
await wrapper.vm.forwardButtonAction();
//Assert
expect(wrapper.vm.$router.navigate).toHaveBeenCalled();
});
test("ForwardButtonAction triggers a router.navigate change if there are capability questions", async () => {
//Arrange
useMainStore().pageData = jest.fn();
useMainStore().pageData.mockReturnValue({
partsOrQuestions: [
{
glassName: "Single",
glassLocation: "Windshield",
parts: [
{
partNumber: "DB12209GTYN",
description: "heated glass, solar, 1 hole",
color: "Green Tint",
requiresRecalibration: false,
requiresCapabilityQuestions: true,
childParts: null,
},
],
partQuestions: null,
},
],
});
useMainStore().lineItems = { glassParts: {} };
useMainStore().vehicle = { carId: "TEST_CAR_ID" };
const { wrapper } = setupMocks({
mountOptionsMockData: {
router: {
navigate: jest.fn(),
},
route: {
query: {
issPage: "vehicle-parts",
},
},
actionList: [
{
actionName: "getCapabilityQuestions",
data: [],
},
],
},
});
wrapper.setData({
selectedGlassParts: { "Rear-Stationary": { partNumber: "DB12209GTYN" } },
});
//Act
vehicleParts.beforeRouteEnter.call(
wrapper.vm,
{ query: { issPage: "vehicle-parts" } },
undefined,
(c) => c(wrapper.vm)
);
await wrapper.vm.forwardButtonAction();
//Assert
expect(wrapper.vm.$router.navigate).toHaveBeenCalled();
});
});
function setupMocks({ pageHeaderWidgetHeaderText = {}, mountOptionsMockData = {} }) {
//Mock api responses
const apiResponses = {
cmsContent: {
SiteSubHeaderWidget: pageHeaderWidgetHeaderText,
VehicleBannerWidget: {
GenericVehicleImage:
"https://digitalisscms-dev.safelite.com/images/default-source/default-album/blurred-image.jpg?sfvrsn=a6ce3034_3",
},
FunnelHeaderWidget: {
LogoImage:
"https://digitalisscms-dev.safelite.com/images/default-source/default-album/safelite-logo.svg?sfvrsn=45e7ed06_3",
},
ColorQuestionWidget: "Please choose your rear window tint color",
FeatureQuestionWidget: "Ok no choose features",
AlertWidget: {
BodyText: "Please choose your tint color",
HeadlineText: "Just a few more steps to go",
},
},
};
const store = useMainStore();
let actionResult = [];
store.getCapabilityQuestions.mockImplementation(() => Promise.resolve({data: actionResult,}));
const apiPromise = Promise.resolve(apiResponses);
settleAllPromises.mockImplementation(() => apiPromise);
fetchCmsContentForPage.mockImplementation(() => Promise.resolve());
const mountOptions = getMountOptions(mountOptionsMockData);
const wrapper = shallowMount(vehicleParts, mountOptions);
const partQuestionRearWrapper = wrapper.findComponent({ name: "glassPartQuestion" });
partQuestionRearWrapper.vm.initializeComponent = glassPartQuestion.methods.initializeComponent;
wrapper.vm.setCmsContent = baseMixin.methods.setCmsContent;
wrapper.vm.$refs.siteFooter.removeLoader = jest.fn();
return { wrapper, apiPromise };
}

View file

@ -0,0 +1,222 @@
<template>
<Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm">
<div class="page-container-grouped-styles vehicle-parts">
<siteHeader ref="siteHeader" cmsWidgetName="SiteHeaderWidget" />
<vehicleBanner
ref="vehicleBanner"
cmsWidgetName="VehicleBannerWidget"
:displayGenericVehicleImage="false" />
<siteSubHeader ref="siteSubHeader" cmsWidgetName="SiteSubHeaderWidget" />
<div class="fade-on-route-transition sub-container make-tall">
<div class="prevent-squish my-5">
<div class="row">
<div class="col">
<alert
class="rounded border-0 shadow-sm"
alertClass="alert-warning"
cmsWidgetName="AlertWidget"
:isDismissible="false" />
</div>
</div>
</div>
<div v-for="(item, i) in PartsOrQuestions" :key="i">
<!-- Render horizontal lines if there is multi-glass (aka if i > 0) -->
<hr v-if="i > 0" />
<glassPartQuestion
:ref="`${RefPrefix}-${item.glassLocation}-${item.glassName}`"
v-model="selectedGlassParts[item.glassLocation + '-' + item.glassName]"
:glassLocation="item.glassLocation"
:glassName="item.glassName"
:colorAnswers="item.colorAnswers"
:alreadyPopulatedPartsData="alreadyPopulatedPartsData" />
</div>
<siteFooter
cmsWidgetName="siteFooterWidget"
ref="siteFooter"
:isForwardActionDisabled="isForwardActionDisabled"
@tempButtonClicked="() => handleTempButtonClicked(this)"
@back-click="navigateBack"
@ForwardClicked="forwardButtonAction" />
</div>
</div>
</Form>
</template>
<script>
// Components
import glassPartQuestion from "@/layouts/vehicle-parts/glass-part-question/glass-part-question";
import siteHeader from "@/common-components/site-header/site-header";
import vehicleBanner from "@/common-components/vehicle-banner/vehicle-banner";
import siteSubHeader from "@/common-components/site-sub-header/site-sub-header";
import siteFooter from "@/common-components/site-footer/site-footer";
import alert from "@/ux-components/alert/alert";
// Supporting Files
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
import { settleAllPromises } from "@/helpers/layout-helper";
import { issPageValues } from "@/router/router-constants/issPage-values";
import { Form } from "vee-validate";
import vehicleQuestionsMixin from "@/mixins/vehicle-questions-mixin";
export default {
name: "vehicle-parts",
mixins: [vehicleQuestionsMixin],
async beforeRouteEnter(to, from, next) {
// Call APIs
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
// Settle promises and get results
const promiseResultMap = [
{
resultKey: "cmsContent",
promise: cmsContentPromise,
},
];
const resultMap = await settleAllPromises(promiseResultMap);
// Call the "next" function to complete the transition to this page.
next((vm) => {
vm.setCmsContent(resultMap.cmsContent);
// Glass Part Question dynamic component
Object.keys(vm.$refs)
.filter((r) => r.includes(vm.RefPrefix) && vm.$refs[r][0] !== undefined)
.forEach((c) =>
vm.$refs[c][0].initializeComponent({
ColorQuestionWidget: resultMap.cmsContent.ColorQuestionWidget,
FeatureQuestionWidget: resultMap.cmsContent.FeatureQuestionWidget,
})
);
});
},
data() {
return {
selectedGlassParts: {},
alertWidgetData: Object,
alreadyPopulatedPartsData: [],
};
},
computed: {
isForwardActionDisabled() {
return (
this.selectedGlassPartNumbers.length !== this.PartsFromApi.partsOrQuestions.length
);
},
selectedGlassPartNumbers() {
// Compile all selected parts from the page.
const numberArray = [];
for (let glassPart of Object.values(this.selectedGlassParts)) {
if (glassPart?.partNumber) {
numberArray.push(glassPart.partNumber);
}
}
return numberArray;
},
PartsOrQuestions() {
const partsData = this.PartsFromApi;
// Map API result data, to vehicle-parts data structure
const mappedData = partsData.partsOrQuestions.map((g) => {
return {
glassName: g.glassName,
glassLocation: g.glassLocation,
colorAnswers: g.parts?.reduce((arr, p) => {
arr.push({
ColorAnswerText: p.color,
FeatureAnswers: [
{
FeatureAnswerText:
p.description === "" ? p.color : p.description,
PartNumber: p.partNumber,
},
],
});
return arr;
}, []),
};
});
return mappedData;
},
PartsFromApi() {
return this.mainStore.pageData(issPageValues.VEHICLE_PARTS);
},
RefPrefix() {
return "partQuestion";
},
},
methods: {
arePagePrerequisitesValid() {
// Check if isRepair is populated and if the pageData we need is here (Parts data)
return (
this.mainStore.damage.isRepair != null &&
this.mainStore.pageData(issPageValues.VEHICLE_PARTS) &&
Object.keys(this.mainStore.pageData(issPageValues.VEHICLE_PARTS)).length !== 0
);
},
async forwardButtonAction() {
const matchedParts = [];
// Match them to the parts from the API.
for (let [key, value] of Object.entries(this.PartsFromApi.partsOrQuestions)) {
for (let [partKey, partValue] of Object.entries(value.parts)) {
const currentPart = this.PartsFromApi.partsOrQuestions[key].parts[partKey];
const isMatched = this.selectedGlassPartNumbers.some(
(p) => p === currentPart.partNumber
);
if (isMatched) {
matchedParts.push({
glassLocation: value.glassLocation,
glassName: value.glassName,
parts: [currentPart],
});
}
}
}
// If no parts could be matched, throw an error (isForwardActionDisabled is based off of matchedParts)
if (this.isForwardActionDisabled) {
this.$refs.funnelFooter.removeLoader();
throw new Error("Could not match any parts to the selected parts");
}
await this.mainStore.resetMoldingAndCapabilityQuestionAnswersIfNeeded(matchedParts);
this.navigateForward(matchedParts, null);
},
LoadInitialPartsData() {
const partsData = this.PartsFromApi;
this.alreadyPopulatedPartsData =
this.mainStore.lineItems.glassParts === null
? []
: this.mainStore.lineItems.glassParts;
partsData.partsOrQuestions.map((g) => {
// If the part is already populated, use the value from the store and populate the v-model.
Object.keys(this.alreadyPopulatedPartsData).forEach((key) => {
const partNumber = this.alreadyPopulatedPartsData[key].partNumber;
g.parts.forEach((p) => {
if (p.partNumber === partNumber) {
this.selectedGlassParts[g.glassLocation + "-" + g.glassName] = p;
}
});
});
});
},
},
mounted() {
this.LoadInitialPartsData();
},
components: {
Form,
glassPartQuestion,
siteHeader,
vehicleBanner,
siteSubHeader,
siteFooter,
alert,
},
};
</script>

View file

@ -6,8 +6,8 @@ import { useMainStore } from "@/store";
describe("year-question.vue", () => {
test("Selected year is emitted upon selection.", async () => {
//Arrange
const { wrapper } = setupMocks({ modelValueProp: "2020" });
const yearToSelect = "2021";
const { wrapper } = setupMocks({ modelValueProp: 2020 });
const yearToSelect = 2021;
//Act
wrapper.setValue({ modelValue: yearToSelect });
@ -15,7 +15,7 @@ describe("year-question.vue", () => {
//Assert
expect(wrapper.emitted()["update:modelValue"][0]).toEqual([
{ modelValue: "2021" },
{ modelValue: 2021 },
]);
});
});
@ -24,7 +24,7 @@ describe("year-question.vue", () => {
test("Data from store api are used as radio question answers.", async () => {
//Arrange
const { wrapper, cmsContent } = setupMocks({
dataFromStoreApi: ["2023", "2022", "2021"],
dataFromStoreApi: [2023, 2022, 2021],
});
//Act
@ -46,7 +46,7 @@ describe("year-question.vue", () => {
function setupMocks({
modelValueProp = "1900",
modelValueProp = 1900,
cmsQuestionText = "CMS text goes here",
dataFromStoreApi = [],
}) {

View file

@ -24,7 +24,7 @@
};
},
props: {
modelValue: String,
modelValue: Number,
cmsWidgetName: String,
},
components: {

View file

@ -1,6 +1,6 @@
import { issPageValues } from "@/router/router-constants/issPage-values";
import { navigationScenarios } from "@/router/router-constants/navigation-scenarios";
import { useMainStore } from "../store";
import { useMainStore } from "@/store";
export default {
methods: {
@ -405,9 +405,7 @@ export default {
// mimic part-questions page data for consistency
for (let partOrQuestion of partsOrQuestions) {
if (this.hasCapabilityQuestions([partOrQuestion])) {
let capabilityQuestionsForGlassLocation = (
await self.mainStore.getCapabilityQuestions(useMainStore().vehicle.carId, partOrQuestion.parts[0].partNumber)
).data;
let capabilityQuestionsForGlassLocation = (await useMainStore().getCapabilityQuestions(useMainStore().vehicle.carId, partOrQuestion.parts[0].partNumber)).data;
capabilityQuestionsForGlassLocation.forEach((question) => {
question.answers = question.answers.map((answer) => {
@ -434,7 +432,7 @@ export default {
const collectedGlassParts = this.reducedGlassPartsArray(partsOrQuestions);
// save to store lineItems.glassParts
self.mainStore.updateGlassParts(collectedGlassParts);
useMainStore().updateGlassParts(collectedGlassParts);
self.$router.navigate(self.navigationScenarios.CLICKED_FORWARD_WITH_NO_MORE_QUESTIONS,self.$route);
}

File diff suppressed because it is too large Load diff

View file

@ -57,12 +57,6 @@ const getDefaultState = () => {
isVerified: false,
},
},
serviceLocation: {
address: null,
city: null,
state: null,
zipCode: null,
},
referralNumber: null,
referralDate: null,
accountNumber: 0,
@ -96,6 +90,7 @@ export const useMainStore = defineStore({
getters: {
vehicle: (state) => state.order.vehicle,
damage: (state) => state.order.damage,
lineItems: (state) => state.order.lineItems,
eventBusItem: (state) => ( eventCategory, eventSubCategory) => {
const matchedEvent = state.applicationUser.eventBus.find(
@ -359,12 +354,38 @@ export const useMainStore = defineStore({
this.applicationUser.pageData[issPageValues.CAPABILITY_QUESTIONS] = null;
},
resetSupportingItemsState() {
this.order.lineItems.supportingItems = null;
},
resetDamageState() {
this.order.damage.isRepair = null;
this.order.damage.numberOfChips = null;
this.order.damage.glassToReplace = null;
},
resetMoldingAndCapabilityQuestionAnswersIfNeeded(matchedParts) {
const partsOrQuestionsDataToCompareWith =
this.pageData(issPageValues.MOLDING_QUESTIONS)?.partsOrQuestions ??
this.pageData(issPageValues.CAPABILITY_QUESTIONS)?.partsOrQuestions ??
[];
const previouslySelectedPartNumbers = getAllPartNumbers(partsOrQuestionsDataToCompareWith);
const currentlySelectedPartNumbers = getAllPartNumbers(matchedParts);
const haveSelectedVehiclePartsChanged =
previouslySelectedPartNumbers !== currentlySelectedPartNumbers;
if (haveSelectedVehiclePartsChanged) {
this.updateGlassParts(null);
this.resetSupportingItemsState();
this.updateMoldingQuestionAnswers(null);
this.updateCapabilityQuestionAnswers(null);
this.updatePageData({ page: issPageValues.MOLDING_QUESTIONS, data: null});
this.updatePageData({ page: issPageValues.CAPABILITY_QUESTIONS, data: null});
}
},
updateVehicleYear(year) {
if(this.order.vehicle.year != year)
{
@ -731,3 +752,14 @@ function convertGlassPieceNamingFromApi(glassArray) {
return glassArray;
}
function getAllPartNumbers(partsOrQuestions) {
return partsOrQuestions[0]?.parts
? [...partsOrQuestions]
.map((glass) => glass.parts)
.flat()
.map((part) => part.partNumber)
.filter((partNumber) => !partNumber.toUpperCase().includes("FEE"))
.sort()
.join(",")
: [];
}