Merge branch 'develop' into feature/CSR-1422
This commit is contained in:
commit
abcabbe1d6
33 changed files with 2069 additions and 246 deletions
|
|
@ -26,8 +26,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: {
|
||||||
statements: 75,
|
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
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// Uncomment this to avoid the massive amount of warnings we are getting for onSubmit and onInvalidSubmit
|
// Uncomment this to avoid the massive amount of warnings we are getting for onSubmit and onInvalidSubmit
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ const GaEvents = {
|
||||||
const GaCategories = {
|
const GaCategories = {
|
||||||
API_RESPONSE: "Api_Response",
|
API_RESPONSE: "Api_Response",
|
||||||
EVOX: "Evox",
|
EVOX: "Evox",
|
||||||
|
FUNNEL_ENTRY: "funnel_entry",
|
||||||
};
|
};
|
||||||
|
|
||||||
const GaActions = {
|
const GaActions = {
|
||||||
|
|
@ -20,6 +21,7 @@ const GaActions = {
|
||||||
VIF: "vif",
|
VIF: "vif",
|
||||||
SUBMITTED: "Submitted",
|
SUBMITTED: "Submitted",
|
||||||
DISPLAYED: "Displayed",
|
DISPLAYED: "Displayed",
|
||||||
|
ZIP_CODE_PROVIDED: "zip_code_provided",
|
||||||
};
|
};
|
||||||
|
|
||||||
const GaLabels = {
|
const GaLabels = {
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,7 @@ const storeActions = {
|
||||||
SAVE_VEHICLE_MAKE: "saveVehicleMake",
|
SAVE_VEHICLE_MAKE: "saveVehicleMake",
|
||||||
SAVE_VEHICLE_MODEL: "saveVehicleModel",
|
SAVE_VEHICLE_MODEL: "saveVehicleModel",
|
||||||
SAVE_VEHICLE_STYLE: "saveVehicleStyle",
|
SAVE_VEHICLE_STYLE: "saveVehicleStyle",
|
||||||
|
SAVE_VEHICLE: "saveVehicle",
|
||||||
SAVE_VEHICLE_DAMAGE: "saveVehicleDamage",
|
SAVE_VEHICLE_DAMAGE: "saveVehicleDamage",
|
||||||
SAVE_VIN_LOOKUP: "saveVinLookup",
|
SAVE_VIN_LOOKUP: "saveVinLookup",
|
||||||
SAVE_SERVICE_ZIP_CODE_INFO: "saveServiceZipCodeInfo",
|
SAVE_SERVICE_ZIP_CODE_INFO: "saveServiceZipCodeInfo",
|
||||||
|
|
|
||||||
|
|
@ -74,6 +74,9 @@ https://safelite.atlassian.net/wiki/spaces/DC/pages/76644418/Button+Question+Com
|
||||||
</div>
|
</div>
|
||||||
<div class="row form-test-error">
|
<div class="row form-test-error">
|
||||||
<error-message
|
<error-message
|
||||||
|
role="comment"
|
||||||
|
aria-atomic="true"
|
||||||
|
aria-live="polite"
|
||||||
class="small mt-1"
|
class="small mt-1"
|
||||||
:name="formatString(groupName)"
|
:name="formatString(groupName)"
|
||||||
v-if="!suppressError"></error-message>
|
v-if="!suppressError"></error-message>
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,8 @@
|
||||||
type="radio"
|
type="radio"
|
||||||
name="day-of-month"
|
name="day-of-month"
|
||||||
v-model="selectedDate"
|
v-model="selectedDate"
|
||||||
@click="fireDateClickedEvent"
|
@click="fireDateSelectedEvent"
|
||||||
|
@keypress.enter="fireDateSelectedEvent"
|
||||||
:value="date.inputValue"
|
:value="date.inputValue"
|
||||||
:id="`${month.monthLabel}-${date.dateNum.toString()}`" />
|
:id="`${month.monthLabel}-${date.dateNum.toString()}`" />
|
||||||
<label :for="`${month.monthLabel}-${date.dateNum.toString()}`">
|
<label :for="`${month.monthLabel}-${date.dateNum.toString()}`">
|
||||||
|
|
@ -56,7 +57,7 @@
|
||||||
:class="[!isLoading ? 'date-picker-hidden' : '']"
|
:class="[!isLoading ? 'date-picker-hidden' : '']"
|
||||||
loaderColor="blue"
|
loaderColor="blue"
|
||||||
loaderPosition="center" />
|
loaderPosition="center" />
|
||||||
<div class="row form-test-error">
|
<div class="row form-test-error" id="date-of-month-error">
|
||||||
<ErrorMessage name="date-of-month" class="small mt-1"></ErrorMessage>
|
<ErrorMessage name="date-of-month" class="small mt-1"></ErrorMessage>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
|
|
@ -190,7 +191,11 @@ export default {
|
||||||
initializeComponent(initialData) {
|
initializeComponent(initialData) {
|
||||||
this.setCalendarData(initialData);
|
this.setCalendarData(initialData);
|
||||||
},
|
},
|
||||||
fireDateClickedEvent() {
|
fireDateSelectedEvent(event) {
|
||||||
|
// Ignore if arrow key selected radioButton
|
||||||
|
if (event.screenX === 0 && event.screenY === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
this.$emit("date-clicked");
|
this.$emit("date-clicked");
|
||||||
},
|
},
|
||||||
getWeekStartDate(dateString) {
|
getWeekStartDate(dateString) {
|
||||||
|
|
@ -685,6 +690,12 @@ export default {
|
||||||
value: newValue,
|
value: newValue,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
errorMessage(newValue, oldValue) {
|
||||||
|
// Check for changing from no error message to some error message.
|
||||||
|
if (newValue && !oldValue) {
|
||||||
|
this.scrollToElement("date-of-month-error");
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
loader,
|
loader,
|
||||||
|
|
@ -700,7 +711,7 @@ export default {
|
||||||
}
|
}
|
||||||
.date-picker {
|
.date-picker {
|
||||||
position: relative;
|
position: relative;
|
||||||
flex-grow: 1;
|
flex-grow: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,14 +16,18 @@
|
||||||
:disabled="isDisabled"
|
:disabled="isDisabled"
|
||||||
:aria-required="isRequired"
|
:aria-required="isRequired"
|
||||||
:validationRules="validationRules"
|
:validationRules="validationRules"
|
||||||
:placeHolderText="placeHolderText">
|
:placeHolderText="placeHolderText"
|
||||||
|
:valueAsKey="valueAsKey">
|
||||||
<option v-if="placeHolderText" value="" selected>{{ placeHolderText }}</option>
|
<option v-if="placeHolderText" value="" selected>{{ placeHolderText }}</option>
|
||||||
<option v-for="(value, name, index) in options" :value="name" :key="index">
|
<option
|
||||||
|
v-for="(value, name, index) in options"
|
||||||
|
:value="valueAsKey == true ? value : name"
|
||||||
|
:key="valueAsKey == true ? value : index">
|
||||||
{{ value }}
|
{{ value }}
|
||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
<div v-show="errorMessage" class="row mt-2 form-test-error">
|
<div v-show="errorMessage" class="row mt-2 form-test-error">
|
||||||
<span role="alert">{{ errorMessage }}</span>
|
<span aria-atomic="true" aria-live="polite">{{ errorMessage }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -47,6 +51,11 @@ export default {
|
||||||
placeHolderText: String,
|
placeHolderText: String,
|
||||||
cmsWidgetName: String,
|
cmsWidgetName: String,
|
||||||
hasError: Boolean,
|
hasError: Boolean,
|
||||||
|
valueAsKey: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
setup(props) {
|
setup(props) {
|
||||||
const uuid = uuidv4();
|
const uuid = uuidv4();
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,8 @@
|
||||||
<div v-show="errorMessage" class="row form-test-error">
|
<div v-show="errorMessage" class="row form-test-error">
|
||||||
<span
|
<span
|
||||||
class="d-inline-flex small my-1"
|
class="d-inline-flex small my-1"
|
||||||
role="alert"
|
aria-atomic="true"
|
||||||
|
aria-live="polite"
|
||||||
:class="[centerErrorMessage ? 'center-error-message' : '']"
|
:class="[centerErrorMessage ? 'center-error-message' : '']"
|
||||||
>{{ errorMessage }}</span
|
>{{ errorMessage }}</span
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -19,15 +19,13 @@
|
||||||
tabindex="-1"
|
tabindex="-1"
|
||||||
aria-labelledby="footerModalLabel"
|
aria-labelledby="footerModalLabel"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
v-on="{ 'show.bs.modal': show, 'hide.bs.modal': hide }"
|
v-on="{ 'show.bs.modal': show, 'hide.bs.modal': hide }">
|
||||||
:style="`height: calc(100% - ${currentFooterAndHeaderHeight}px);`">
|
|
||||||
<div class="menu-modal-container">
|
<div class="menu-modal-container">
|
||||||
<button
|
<button
|
||||||
class="menu-button"
|
class="menu-button"
|
||||||
type="button"
|
type="button"
|
||||||
:class="[isActive ? 'active' : '']"
|
:class="[isActive ? 'active' : '']"
|
||||||
data-bs-toggle="modal"
|
@click="toggleModal"
|
||||||
data-bs-target="#footerModal"
|
|
||||||
aria-label="Hamburger Menu (modal window)">
|
aria-label="Hamburger Menu (modal window)">
|
||||||
<div class="bar1"></div>
|
<div class="bar1"></div>
|
||||||
<div class="bar2"></div>
|
<div class="bar2"></div>
|
||||||
|
|
@ -86,7 +84,6 @@ export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
isActive: false,
|
isActive: false,
|
||||||
currentFooterAndHeaderHeight: 0,
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
@ -104,7 +101,6 @@ export default {
|
||||||
Modal.getInstance(document.getElementById("footerModal")).hide();
|
Modal.getInstance(document.getElementById("footerModal")).hide();
|
||||||
},
|
},
|
||||||
show() {
|
show() {
|
||||||
this.currentFooterAndHeaderHeight = this.getFooterInfoBoxHeight() + 72;
|
|
||||||
this.isActive = true;
|
this.isActive = true;
|
||||||
this.scrollToPageTop();
|
this.scrollToPageTop();
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -338,12 +338,10 @@ export default {
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
await this.dispatchStoreAction(
|
await this.dispatchStoreAction(
|
||||||
storeActions.SAVE_SERVICE_LOCATION,
|
storeActions.SAVE_SERVICE_ZIP_CODE_INFO,
|
||||||
{
|
{
|
||||||
address: this.customerQuestions.addressQuestions.streetAddress,
|
|
||||||
city: this.customerQuestions.addressQuestions.city,
|
|
||||||
zipCode: this.serviceZipCode,
|
|
||||||
state: resultMap.serviceZipValidationResponse.state,
|
state: resultMap.serviceZipValidationResponse.state,
|
||||||
|
zipCode: this.serviceZipCode,
|
||||||
zipCodeCtu: resultMap.serviceZipValidationResponse.zipCodeCtu,
|
zipCodeCtu: resultMap.serviceZipValidationResponse.zipCodeCtu,
|
||||||
},
|
},
|
||||||
false
|
false
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,6 @@ import customerDetails from "@/layouts/customer-details/customer-details.vue";
|
||||||
// Supporting Files
|
// Supporting Files
|
||||||
import { shallowMount } from "@vue/test-utils";
|
import { shallowMount } from "@vue/test-utils";
|
||||||
import { getMountOptions } from "@/helpers/unit-test-helper.js";
|
import { getMountOptions } from "@/helpers/unit-test-helper.js";
|
||||||
import * as navigateToHeritage from "@/helpers/heritage-integration/navigation-helper";
|
|
||||||
|
|
||||||
jest.mock("@/helpers/heritage-integration/navigation-helper", () => ({
|
|
||||||
navigateToHeritageFunnel: jest.fn(),
|
|
||||||
}));
|
|
||||||
|
|
||||||
// Mock our module for promises.
|
// Mock our module for promises.
|
||||||
jest.mock("@/helpers/layout-helper.js", () => ({
|
jest.mock("@/helpers/layout-helper.js", () => ({
|
||||||
|
|
@ -36,7 +31,7 @@ describe("customer-details.vue", () => {
|
||||||
await wrapper.vm.forwardButtonAction();
|
await wrapper.vm.forwardButtonAction();
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(wrapper.vm.$router.navigateWithoutSaving).toHaveBeenCalled();
|
expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -150,7 +150,7 @@ export default {
|
||||||
(store.getters.order.damage.isRepair ||
|
(store.getters.order.damage.isRepair ||
|
||||||
(store.getters.order.lineItems?.glassParts != null &&
|
(store.getters.order.lineItems?.glassParts != null &&
|
||||||
store.getters.order.lineItems.glassParts.length > 0)) &&
|
store.getters.order.lineItems.glassParts.length > 0)) &&
|
||||||
!store.getters.payment.insuranceCoverage.isVerified
|
store.getters.order.referralNumber?.length !== 6
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
getDefaultIsInsuranceSelectedValue(availableLineItems) {
|
getDefaultIsInsuranceSelectedValue(availableLineItems) {
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
<textBlock
|
<textBlock
|
||||||
:cmsWidgetName="headerCmsWidgetName"
|
:cmsWidgetName="headerCmsWidgetName"
|
||||||
typeStyle="body small bold dark"
|
typeStyle="body small bold dark"
|
||||||
margin="mt-0" />
|
marginTopSizeOverride="0" />
|
||||||
<textLink
|
<textLink
|
||||||
linkType="textSmall"
|
linkType="textSmall"
|
||||||
text="Edit"
|
text="Edit"
|
||||||
|
|
@ -12,9 +12,12 @@
|
||||||
@click-event="linkClicked"
|
@click-event="linkClicked"
|
||||||
href="javascript:void(0)" />
|
href="javascript:void(0)" />
|
||||||
</div>
|
</div>
|
||||||
<div class="small" v-for="item in content" :key="item" data-test="contentLine">
|
<div
|
||||||
{{ item }}
|
class="small review-block-content"
|
||||||
</div>
|
v-for="item in content"
|
||||||
|
:key="item"
|
||||||
|
data-test="contentLine"
|
||||||
|
v-html="item"></div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
@ -44,3 +47,9 @@ export default {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
:deep(.review-block-content > ul) {
|
||||||
|
margin-bottom: 0rem;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,258 @@
|
||||||
import { shallowMount } from "@vue/test-utils";
|
import { shallowMount } from "@vue/test-utils";
|
||||||
import { getMountOptions } from "@/helpers/unit-test-helper.js";
|
import { getMountOptions } from "@/helpers/unit-test-helper.js";
|
||||||
import damageReview from "@/layouts/review/review-sections/damage-review/damage-review";
|
|
||||||
|
|
||||||
jest.mock("@/helpers/cms-content-helper", () => ({
|
import damageReview from "@/layouts/review/review-sections/damage-review/damage-review";
|
||||||
fetchCmsContentForPage: () => Promise.resolve("content"),
|
import { damageLocationsSelected as glassConstants } from "@/constants/damage-locations-selected";
|
||||||
}));
|
|
||||||
|
const testConstants = {
|
||||||
|
cmsConstants: {
|
||||||
|
widgetNames: {
|
||||||
|
header: "DamageReviewWidget",
|
||||||
|
locations: "DamageLocationsWidget",
|
||||||
|
driverDamages: "DriverDamagesWidget",
|
||||||
|
passengerDamages: "PassengerDamagesWidget",
|
||||||
|
},
|
||||||
|
header: {
|
||||||
|
text: "Damage",
|
||||||
|
},
|
||||||
|
damageLocations: {
|
||||||
|
windshield: glassConstants.WINDSHIELD,
|
||||||
|
driver: glassConstants.DRIVER,
|
||||||
|
passenger: glassConstants.PASSENGER,
|
||||||
|
rear: glassConstants.REAR,
|
||||||
|
},
|
||||||
|
damageNames: {
|
||||||
|
vent: glassConstants.VENT,
|
||||||
|
front: glassConstants.FRONT,
|
||||||
|
back: glassConstants.BACK,
|
||||||
|
quarter: glassConstants.QUARTER,
|
||||||
|
side: glassConstants.SIDEDOOR,
|
||||||
|
},
|
||||||
|
locationCopy: {
|
||||||
|
windshield: "Windshield copy",
|
||||||
|
driver: "Driver copy",
|
||||||
|
passenger: "Passenger copy",
|
||||||
|
rear: "Rear copy",
|
||||||
|
},
|
||||||
|
damageCopy: {
|
||||||
|
vent: "Vent copy",
|
||||||
|
front: "Front copy",
|
||||||
|
back: "Back copy",
|
||||||
|
quarter: "Quarter copy",
|
||||||
|
side: "Side copy",
|
||||||
|
},
|
||||||
|
imageId: "00000000-0000-0000-0000-000000000000",
|
||||||
|
},
|
||||||
|
makeBulletedList: (items) => {
|
||||||
|
let list = "<ul>";
|
||||||
|
items.forEach((item) => {
|
||||||
|
list += `<li>${item}</li>`;
|
||||||
|
});
|
||||||
|
list += "</ul>";
|
||||||
|
|
||||||
|
return list;
|
||||||
|
},
|
||||||
|
glassItems: {
|
||||||
|
windshield: {
|
||||||
|
glassLocation: glassConstants.WINDSHIELD,
|
||||||
|
glassName: glassConstants.SINGLE,
|
||||||
|
},
|
||||||
|
rear: {
|
||||||
|
glassLocation: glassConstants.REAR,
|
||||||
|
glassName: glassConstants.STATIONARY,
|
||||||
|
},
|
||||||
|
passengerItems: {
|
||||||
|
vent: {
|
||||||
|
glassLocation: glassConstants.PASSENGER,
|
||||||
|
glassName: glassConstants.VENT,
|
||||||
|
},
|
||||||
|
front: {
|
||||||
|
glassLocation: glassConstants.PASSENGER,
|
||||||
|
glassName: glassConstants.FRONT,
|
||||||
|
},
|
||||||
|
back: {
|
||||||
|
glassLocation: glassConstants.PASSENGER,
|
||||||
|
glassName: glassConstants.BACK,
|
||||||
|
},
|
||||||
|
quarter: {
|
||||||
|
glassLocation: glassConstants.PASSENGER,
|
||||||
|
glassName: glassConstants.QUARTER,
|
||||||
|
},
|
||||||
|
side: {
|
||||||
|
glassLocation: glassConstants.PASSENGER,
|
||||||
|
glassName: glassConstants.SIDEDOOR,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
driverItems: {
|
||||||
|
vent: {
|
||||||
|
glassLocation: glassConstants.DRIVER,
|
||||||
|
glassName: glassConstants.VENT,
|
||||||
|
},
|
||||||
|
front: {
|
||||||
|
glassLocation: glassConstants.DRIVER,
|
||||||
|
glassName: glassConstants.FRONT,
|
||||||
|
},
|
||||||
|
back: {
|
||||||
|
glassLocation: glassConstants.DRIVER,
|
||||||
|
glassName: glassConstants.BACK,
|
||||||
|
},
|
||||||
|
quarter: {
|
||||||
|
glassLocation: glassConstants.DRIVER,
|
||||||
|
glassName: glassConstants.QUARTER,
|
||||||
|
},
|
||||||
|
side: {
|
||||||
|
glassLocation: glassConstants.DRIVER,
|
||||||
|
glassName: glassConstants.SIDEDOOR,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let cmsContent;
|
||||||
|
|
||||||
describe("Damage Review Block", () => {
|
describe("Damage Review Block", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
cmsContent = {
|
||||||
|
DamageReviewWidget: {
|
||||||
|
Text: testConstants.cmsConstants.header.text,
|
||||||
|
},
|
||||||
|
DamageLocationsWidget: {
|
||||||
|
Answers: [
|
||||||
|
{
|
||||||
|
Name: testConstants.cmsConstants.damageLocations.windshield,
|
||||||
|
Text: testConstants.cmsConstants.locationCopy.windshield,
|
||||||
|
SubText: "",
|
||||||
|
ImageId: testConstants.cmsConstants.imageId,
|
||||||
|
Image: "",
|
||||||
|
SubWidgetName: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: testConstants.cmsConstants.damageLocations.driver,
|
||||||
|
Text: testConstants.cmsConstants.locationCopy.driver,
|
||||||
|
SubText: "",
|
||||||
|
ImageId: testConstants.cmsConstants.imageId,
|
||||||
|
Image: "",
|
||||||
|
SubWidgetName: testConstants.cmsConstants.widgetNames.driverDamages,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: testConstants.cmsConstants.damageLocations.passenger,
|
||||||
|
Text: testConstants.cmsConstants.locationCopy.passenger,
|
||||||
|
SubText: "",
|
||||||
|
ImageId: testConstants.cmsConstants.imageId,
|
||||||
|
Image: "",
|
||||||
|
SubWidgetName: testConstants.cmsConstants.widgetNames.passengerDamages,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: testConstants.cmsConstants.damageLocations.rear,
|
||||||
|
Text: testConstants.cmsConstants.locationCopy.rear,
|
||||||
|
SubText: "",
|
||||||
|
ImageId: testConstants.cmsConstants.imageId,
|
||||||
|
Image: "",
|
||||||
|
SubWidgetName: "",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
DriverDamagesWidget: {
|
||||||
|
Answers: [
|
||||||
|
{
|
||||||
|
Name: testConstants.cmsConstants.damageNames.vent,
|
||||||
|
Text: testConstants.cmsConstants.damageCopy.vent,
|
||||||
|
SubText: "",
|
||||||
|
ImageId: testConstants.cmsConstants.imageId,
|
||||||
|
Image: "",
|
||||||
|
SubWidgetName: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: testConstants.cmsConstants.damageNames.front,
|
||||||
|
Text: testConstants.cmsConstants.damageCopy.front,
|
||||||
|
SubText: "",
|
||||||
|
ImageId: testConstants.cmsConstants.imageId,
|
||||||
|
Image: "",
|
||||||
|
SubWidgetName: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: testConstants.cmsConstants.damageNames.back,
|
||||||
|
Text: testConstants.cmsConstants.damageCopy.back,
|
||||||
|
SubText: "",
|
||||||
|
ImageId: testConstants.cmsConstants.imageId,
|
||||||
|
Image: "",
|
||||||
|
SubWidgetName: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: testConstants.cmsConstants.damageNames.quarter,
|
||||||
|
Text: testConstants.cmsConstants.damageCopy.quarter,
|
||||||
|
SubText: "",
|
||||||
|
ImageId: testConstants.cmsConstants.imageId,
|
||||||
|
Image: "",
|
||||||
|
SubWidgetName: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: testConstants.cmsConstants.damageNames.side,
|
||||||
|
Text: testConstants.cmsConstants.damageCopy.side,
|
||||||
|
SubText: "",
|
||||||
|
ImageId: testConstants.cmsConstants.imageId,
|
||||||
|
Image: "",
|
||||||
|
SubWidgetName: "",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
PassengerDamagesWidget: {
|
||||||
|
Answers: [
|
||||||
|
{
|
||||||
|
Name: testConstants.cmsConstants.damageNames.vent,
|
||||||
|
Text: testConstants.cmsConstants.damageCopy.vent,
|
||||||
|
SubText: "",
|
||||||
|
ImageId: testConstants.cmsConstants.imageId,
|
||||||
|
Image: "",
|
||||||
|
SubWidgetName: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: testConstants.cmsConstants.damageNames.front,
|
||||||
|
Text: testConstants.cmsConstants.damageCopy.front,
|
||||||
|
SubText: "",
|
||||||
|
ImageId: testConstants.cmsConstants.imageId,
|
||||||
|
Image: "",
|
||||||
|
SubWidgetName: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: testConstants.cmsConstants.damageNames.back,
|
||||||
|
Text: testConstants.cmsConstants.damageCopy.back,
|
||||||
|
SubText: "",
|
||||||
|
ImageId: testConstants.cmsConstants.imageId,
|
||||||
|
Image: "",
|
||||||
|
SubWidgetName: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: testConstants.cmsConstants.damageNames.quarter,
|
||||||
|
Text: testConstants.cmsConstants.damageCopy.quarter,
|
||||||
|
SubText: "",
|
||||||
|
ImageId: testConstants.cmsConstants.imageId,
|
||||||
|
Image: "",
|
||||||
|
SubWidgetName: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: testConstants.cmsConstants.damageNames.side,
|
||||||
|
Text: testConstants.cmsConstants.damageCopy.side,
|
||||||
|
SubText: "",
|
||||||
|
ImageId: testConstants.cmsConstants.imageId,
|
||||||
|
Image: "",
|
||||||
|
SubWidgetName: "",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
describe("Correctly assembles damage info into a display string", () => {
|
describe("Correctly assembles damage info into a display string", () => {
|
||||||
test("Basic Replace", async () => {
|
test("Shows windshield copy when windshield damage is included", async () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const { wrapper } = setupMocks({
|
const { wrapper } = setupMocks({
|
||||||
propsData: {
|
propsData: {
|
||||||
|
cmsWidgetName: testConstants.cmsConstants.widgetNames.header,
|
||||||
|
damageLocationsWidgetName: testConstants.cmsConstants.widgetNames.locations,
|
||||||
damage: {
|
damage: {
|
||||||
isRepair: false,
|
isRepair: false,
|
||||||
|
glassToReplace: [testConstants.glassItems.windshield],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
@ -22,16 +261,21 @@ describe("Damage Review Block", () => {
|
||||||
await wrapper.vm.$nextTick();
|
await wrapper.vm.$nextTick();
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(wrapper.vm.displayContent).toStrictEqual(["Windshield crack"]);
|
expect(wrapper.vm.displayContent).toStrictEqual([
|
||||||
|
testConstants.cmsConstants.locationCopy.windshield,
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Basic Repair", async () => {
|
test("Windshield copy is shown when order is a repair", async () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const { wrapper } = setupMocks({
|
const { wrapper } = setupMocks({
|
||||||
propsData: {
|
propsData: {
|
||||||
|
cmsWidgetName: testConstants.cmsConstants.widgetNames.header,
|
||||||
|
damageLocationsWidgetName: testConstants.cmsConstants.widgetNames.locations,
|
||||||
damage: {
|
damage: {
|
||||||
isRepair: true,
|
isRepair: true,
|
||||||
numberOfChips: 2,
|
numberOfChips: 2,
|
||||||
|
glassToReplace: [],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
@ -40,16 +284,21 @@ describe("Damage Review Block", () => {
|
||||||
await wrapper.vm.$nextTick();
|
await wrapper.vm.$nextTick();
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(wrapper.vm.displayContent).toStrictEqual(["Windshield repair - 2 chips"]);
|
expect(wrapper.vm.displayContent).toStrictEqual([
|
||||||
|
testConstants.cmsConstants.locationCopy.windshield,
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Basic Repair - no s with 1 chip", async () => {
|
test("Rear windshield copy shows when rear damage is present", async () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const { wrapper } = setupMocks({
|
const { wrapper } = setupMocks({
|
||||||
propsData: {
|
propsData: {
|
||||||
|
cmsWidgetName: testConstants.cmsConstants.widgetNames.header,
|
||||||
|
damageLocationsWidgetName: testConstants.cmsConstants.widgetNames.locations,
|
||||||
damage: {
|
damage: {
|
||||||
isRepair: true,
|
isRepair: false,
|
||||||
numberOfChips: 1,
|
numberOfChips: null,
|
||||||
|
glassToReplace: [testConstants.glassItems.rear],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
@ -58,7 +307,116 @@ describe("Damage Review Block", () => {
|
||||||
await wrapper.vm.$nextTick();
|
await wrapper.vm.$nextTick();
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(wrapper.vm.displayContent).toStrictEqual(["Windshield repair - 1 chip"]);
|
expect(wrapper.vm.displayContent).toStrictEqual([
|
||||||
|
testConstants.cmsConstants.locationCopy.rear,
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Driver side copy and items are shown when driver side damage is present", async () => {
|
||||||
|
// Arrange
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
propsData: {
|
||||||
|
cmsWidgetName: testConstants.cmsConstants.widgetNames.header,
|
||||||
|
damageLocationsWidgetName: testConstants.cmsConstants.widgetNames.locations,
|
||||||
|
damage: {
|
||||||
|
isRepair: false,
|
||||||
|
numberOfChips: null,
|
||||||
|
glassToReplace: [
|
||||||
|
testConstants.glassItems.driverItems.back,
|
||||||
|
testConstants.glassItems.driverItems.front,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await wrapper.vm.$nextTick();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(wrapper.vm.displayContent).toStrictEqual([
|
||||||
|
testConstants.cmsConstants.locationCopy.driver,
|
||||||
|
testConstants.makeBulletedList([
|
||||||
|
testConstants.cmsConstants.damageCopy.front,
|
||||||
|
testConstants.cmsConstants.damageCopy.back,
|
||||||
|
]),
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Passenger side copy and items are shown when passenger side damage is present", async () => {
|
||||||
|
// Arrange
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
propsData: {
|
||||||
|
cmsWidgetName: testConstants.cmsConstants.widgetNames.header,
|
||||||
|
damageLocationsWidgetName: testConstants.cmsConstants.widgetNames.locations,
|
||||||
|
damage: {
|
||||||
|
isRepair: false,
|
||||||
|
numberOfChips: null,
|
||||||
|
glassToReplace: [
|
||||||
|
testConstants.glassItems.passengerItems.quarter,
|
||||||
|
testConstants.glassItems.passengerItems.vent,
|
||||||
|
testConstants.glassItems.passengerItems.side,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await wrapper.vm.$nextTick();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(wrapper.vm.displayContent).toStrictEqual([
|
||||||
|
testConstants.cmsConstants.locationCopy.passenger,
|
||||||
|
testConstants.makeBulletedList([
|
||||||
|
testConstants.cmsConstants.damageCopy.vent,
|
||||||
|
testConstants.cmsConstants.damageCopy.quarter,
|
||||||
|
testConstants.cmsConstants.damageCopy.side,
|
||||||
|
]),
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("All relevant sections are shown in order in multiglass scenario", async () => {
|
||||||
|
// Arrange
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
propsData: {
|
||||||
|
cmsWidgetName: testConstants.cmsConstants.widgetNames.header,
|
||||||
|
damageLocationsWidgetName: testConstants.cmsConstants.widgetNames.locations,
|
||||||
|
damage: {
|
||||||
|
isRepair: false,
|
||||||
|
numberOfChips: null,
|
||||||
|
glassToReplace: [
|
||||||
|
testConstants.glassItems.windshield,
|
||||||
|
testConstants.glassItems.rear,
|
||||||
|
testConstants.glassItems.driverItems.vent,
|
||||||
|
testConstants.glassItems.driverItems.front,
|
||||||
|
testConstants.glassItems.driverItems.back,
|
||||||
|
testConstants.glassItems.passengerItems.quarter,
|
||||||
|
testConstants.glassItems.passengerItems.back,
|
||||||
|
testConstants.glassItems.passengerItems.side,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await wrapper.vm.$nextTick();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(wrapper.vm.displayContent).toStrictEqual([
|
||||||
|
testConstants.cmsConstants.locationCopy.windshield,
|
||||||
|
testConstants.cmsConstants.locationCopy.driver,
|
||||||
|
testConstants.makeBulletedList([
|
||||||
|
testConstants.cmsConstants.damageCopy.vent,
|
||||||
|
testConstants.cmsConstants.damageCopy.front,
|
||||||
|
testConstants.cmsConstants.damageCopy.back,
|
||||||
|
]),
|
||||||
|
testConstants.cmsConstants.locationCopy.passenger,
|
||||||
|
testConstants.makeBulletedList([
|
||||||
|
testConstants.cmsConstants.damageCopy.back,
|
||||||
|
testConstants.cmsConstants.damageCopy.quarter,
|
||||||
|
testConstants.cmsConstants.damageCopy.side,
|
||||||
|
]),
|
||||||
|
testConstants.cmsConstants.locationCopy.rear,
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
@ -66,6 +424,16 @@ describe("Damage Review Block", () => {
|
||||||
function setupMocks(customMountOptions) {
|
function setupMocks(customMountOptions) {
|
||||||
const mountOptions = getMountOptions(customMountOptions);
|
const mountOptions = getMountOptions(customMountOptions);
|
||||||
|
|
||||||
|
const mockMixin = {
|
||||||
|
methods: {
|
||||||
|
getCmsContent: jest.fn((widgetName, cmsFieldName) => {
|
||||||
|
return cmsContent?.[widgetName]?.[cmsFieldName] ?? "";
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
mountOptions.global.mixins = [mockMixin];
|
||||||
|
|
||||||
const wrapper = shallowMount(damageReview, mountOptions);
|
const wrapper = shallowMount(damageReview, mountOptions);
|
||||||
wrapper.vm.setCmsContent = jest.fn();
|
wrapper.vm.setCmsContent = jest.fn();
|
||||||
return { wrapper };
|
return { wrapper };
|
||||||
|
|
|
||||||
|
|
@ -7,11 +7,13 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import reviewBlock from "@/layouts/review/review-block/review-block";
|
import reviewBlock from "@/layouts/review/review-block/review-block";
|
||||||
|
import { damageLocationsSelected } from "@/constants/damage-locations-selected.js";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "damage-review",
|
name: "damage-review",
|
||||||
props: {
|
props: {
|
||||||
cmsWidgetName: String,
|
cmsWidgetName: String,
|
||||||
|
damageLocationsWidgetName: String,
|
||||||
damage: Object,
|
damage: Object,
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
|
|
@ -21,17 +23,115 @@ export default {
|
||||||
editClicked() {
|
editClicked() {
|
||||||
this.$emit("edit-clicked");
|
this.$emit("edit-clicked");
|
||||||
},
|
},
|
||||||
|
getAnswersNullSafe(widgetName) {
|
||||||
|
const rawAnswers = this.getCmsContent(widgetName, "Answers");
|
||||||
|
|
||||||
|
return rawAnswers ? rawAnswers : [];
|
||||||
|
},
|
||||||
|
getLocationAnswer(damageLocation) {
|
||||||
|
return this.locationAnswers?.find((answer) => answer.Name === damageLocation);
|
||||||
|
},
|
||||||
|
getGlassPieces(damageLocation) {
|
||||||
|
return this.damage?.glassToReplace?.filter(
|
||||||
|
(item) => item.glassLocation === damageLocation
|
||||||
|
);
|
||||||
|
},
|
||||||
|
generateBulletedListFromAnswers(answers) {
|
||||||
|
let list = "<ul>";
|
||||||
|
|
||||||
|
answers.forEach((answer) => {
|
||||||
|
list += `<li>${answer.Text}</li>`;
|
||||||
|
});
|
||||||
|
|
||||||
|
list += "</ul>";
|
||||||
|
|
||||||
|
return list;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
displayContent() {
|
displayContent() {
|
||||||
return [
|
return [
|
||||||
this.damage.isRepair
|
...this.windshieldCopy,
|
||||||
? `Windshield repair - ${this.damage.numberOfChips} chip${
|
...this.driverSideCopy,
|
||||||
this.damage.numberOfChips !== 1 ? "s" : ""
|
...this.passengerSideCopy,
|
||||||
}`
|
...this.rearCopy,
|
||||||
: "Windshield crack",
|
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
|
hasWindshieldDamage() {
|
||||||
|
const windshieldPieces = this.getGlassPieces(damageLocationsSelected.WINDSHIELD);
|
||||||
|
|
||||||
|
return this.damage.isRepair || !!windshieldPieces?.length;
|
||||||
|
},
|
||||||
|
hasDriverSideDamage() {
|
||||||
|
const driverPieces = this.getGlassPieces(damageLocationsSelected.DRIVER);
|
||||||
|
|
||||||
|
return !!driverPieces?.length;
|
||||||
|
},
|
||||||
|
hasPassengerSideDamage() {
|
||||||
|
const passengerPieces = this.getGlassPieces(damageLocationsSelected.PASSENGER);
|
||||||
|
|
||||||
|
return !!passengerPieces?.length;
|
||||||
|
},
|
||||||
|
hasRearDamage() {
|
||||||
|
const rearPieces = this.getGlassPieces(damageLocationsSelected.REAR);
|
||||||
|
|
||||||
|
return !!rearPieces?.length;
|
||||||
|
},
|
||||||
|
windshieldCopy() {
|
||||||
|
const answerContent = this.getLocationAnswer(damageLocationsSelected.WINDSHIELD);
|
||||||
|
|
||||||
|
if (this.hasWindshieldDamage) {
|
||||||
|
return [answerContent?.Text];
|
||||||
|
} else {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
driverSideCopy() {
|
||||||
|
const answerContent = this.getLocationAnswer(damageLocationsSelected.DRIVER);
|
||||||
|
const damageAnswers = this.getAnswersNullSafe(answerContent?.SubWidgetName);
|
||||||
|
const driverSideItems = this.getGlassPieces(damageLocationsSelected.DRIVER);
|
||||||
|
const damageAnswersOnOrder = damageAnswers?.filter((answer) =>
|
||||||
|
driverSideItems?.some((glassPiece) => answer.Name === glassPiece.glassName)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (this.hasDriverSideDamage) {
|
||||||
|
return [
|
||||||
|
answerContent?.Text,
|
||||||
|
this.generateBulletedListFromAnswers(damageAnswersOnOrder),
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
passengerSideCopy() {
|
||||||
|
const answerContent = this.getLocationAnswer(damageLocationsSelected.PASSENGER);
|
||||||
|
const damageAnswers = this.getAnswersNullSafe(answerContent?.SubWidgetName);
|
||||||
|
const passengerSideItems = this.getGlassPieces(damageLocationsSelected.PASSENGER);
|
||||||
|
const damageAnswersOnOrder = damageAnswers?.filter((answer) =>
|
||||||
|
passengerSideItems?.some((glassPiece) => answer.Name === glassPiece.glassName)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (this.hasPassengerSideDamage) {
|
||||||
|
return [
|
||||||
|
answerContent?.Text,
|
||||||
|
this.generateBulletedListFromAnswers(damageAnswersOnOrder),
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
rearCopy() {
|
||||||
|
const answerContent = this.getLocationAnswer(damageLocationsSelected.REAR);
|
||||||
|
|
||||||
|
if (this.hasRearDamage) {
|
||||||
|
return [answerContent?.Text];
|
||||||
|
} else {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
locationAnswers() {
|
||||||
|
return this.getAnswersNullSafe(this.damageLocationsWidgetName);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
reviewBlock,
|
reviewBlock,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,129 @@
|
||||||
|
import { shallowMount } from "@vue/test-utils";
|
||||||
|
import { getMountOptions } from "@/helpers/unit-test-helper.js";
|
||||||
|
import serviceLocationReview from "@/layouts/review/review-sections/service-location-review/service-location-review";
|
||||||
|
|
||||||
|
import { AppointmentTypeStrings } from "@/constants/schedule-constants";
|
||||||
|
|
||||||
|
const cmsContent = {
|
||||||
|
ServiceLocationTitleWidget: {
|
||||||
|
Text: "Title Text",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
describe("Service Location Review Block", () => {
|
||||||
|
it("Should render mobile address if mobile appointment", async () => {
|
||||||
|
// Arrange
|
||||||
|
const props = generateDefaultProps();
|
||||||
|
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
propsData: props,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await wrapper.vm.$nextTick();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(wrapper.vm.displayContent).toEqual([
|
||||||
|
"Mobile Address 1, Mobile Address 2, Mobile City, MO 11111",
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should render service location address if inshop appointment.", async () => {
|
||||||
|
// Arrange
|
||||||
|
let props = generateDefaultProps();
|
||||||
|
|
||||||
|
props.serviceLocation.appointmentType = AppointmentTypeStrings.IN_SHOP;
|
||||||
|
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
propsData: props,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await wrapper.vm.$nextTick();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(wrapper.vm.displayContent).toEqual([
|
||||||
|
"Service Location Address, Service Location City, SL 22222",
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should render service location address if drop-off appointment", async () => {
|
||||||
|
// Arrange
|
||||||
|
let props = generateDefaultProps();
|
||||||
|
|
||||||
|
props.serviceLocation.appointmentType = AppointmentTypeStrings.DROP_OFF;
|
||||||
|
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
propsData: props,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await wrapper.vm.$nextTick();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(wrapper.vm.displayContent).toEqual([
|
||||||
|
"Service Location Address, Service Location City, SL 22222",
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should not add comma or any text if address2 is null", async () => {
|
||||||
|
// Arrange
|
||||||
|
let props = generateDefaultProps();
|
||||||
|
|
||||||
|
props.serviceLocation.address2 = null;
|
||||||
|
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
propsData: props,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await wrapper.vm.$nextTick();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(wrapper.vm.displayContent).toEqual(["Mobile Address 1, Mobile City, MO 11111"]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function generateDefaultProps() {
|
||||||
|
return {
|
||||||
|
cmsWidgetName: "ServiceLocationTitleWidget",
|
||||||
|
serviceLocation: {
|
||||||
|
address: "Mobile Address 1",
|
||||||
|
address2: "Mobile Address 2",
|
||||||
|
city: "Mobile City",
|
||||||
|
state: "MO",
|
||||||
|
zipCode: "11111",
|
||||||
|
zipCodeCtu: "",
|
||||||
|
appointmentType: AppointmentTypeStrings.MOBILE,
|
||||||
|
isVehicleProtected: false,
|
||||||
|
provider: {
|
||||||
|
providerNumber: "",
|
||||||
|
address: {
|
||||||
|
streetAddress: "Service Location Address",
|
||||||
|
city: "Service Location City",
|
||||||
|
state: "SL",
|
||||||
|
zipCode: "22222",
|
||||||
|
zipCodeCtu: "",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function setupMocks(customMountOptions) {
|
||||||
|
const mountOptions = getMountOptions(customMountOptions);
|
||||||
|
|
||||||
|
const mockMixin = {
|
||||||
|
methods: {
|
||||||
|
getCmsContent: jest.fn((widgetName, cmsFieldName) => {
|
||||||
|
return cmsContent?.[widgetName]?.[cmsFieldName] ?? "";
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
mountOptions.global.mixins = [mockMixin];
|
||||||
|
|
||||||
|
const wrapper = shallowMount(serviceLocationReview, mountOptions);
|
||||||
|
wrapper.vm.setCmsContent = jest.fn();
|
||||||
|
return { wrapper };
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,58 @@
|
||||||
|
<template>
|
||||||
|
<reviewBlock
|
||||||
|
:headerCmsWidgetName="cmsWidgetName"
|
||||||
|
:content="displayContent"
|
||||||
|
@edit-clicked="editClicked" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import reviewBlock from "@/layouts/review/review-block/review-block";
|
||||||
|
import { AppointmentTypeStrings } from "@/constants/schedule-constants";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "service-package-review",
|
||||||
|
props: {
|
||||||
|
cmsWidgetName: String,
|
||||||
|
serviceLocation: Object,
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
editClicked() {
|
||||||
|
this.$emit("edit-clicked");
|
||||||
|
},
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
displayContent() {
|
||||||
|
return [
|
||||||
|
`${this.addressInfo.address}${this.addressInfo.address2 ? ", " : ""}${
|
||||||
|
this.addressInfo.address2
|
||||||
|
}, ${this.addressInfo.city}, ${this.addressInfo.state} ${this.addressInfo.zipCode}`,
|
||||||
|
];
|
||||||
|
},
|
||||||
|
addressInfo() {
|
||||||
|
if (this.serviceLocation?.appointmentType === AppointmentTypeStrings.MOBILE) {
|
||||||
|
return {
|
||||||
|
address: this.serviceLocation?.address,
|
||||||
|
address2: this.serviceLocation?.address2 ?? "",
|
||||||
|
city: this.serviceLocation?.city,
|
||||||
|
state: this.serviceLocation?.state,
|
||||||
|
zipCode: this.serviceLocation?.zipCode,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
address: this.serviceLocation?.provider?.address?.streetAddress,
|
||||||
|
address2: "",
|
||||||
|
city: this.serviceLocation?.provider?.address?.city,
|
||||||
|
state: this.serviceLocation?.provider?.address?.state,
|
||||||
|
zipCode: this.serviceLocation?.provider?.address?.zipCode,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
reviewBlock,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
@ -77,11 +77,8 @@ const figmaScenarios = [
|
||||||
{
|
{
|
||||||
name: "05_01_CSR_Quote_Cash",
|
name: "05_01_CSR_Quote_Cash",
|
||||||
params: {
|
params: {
|
||||||
availableVaps: [
|
wiperResponse: [testConstants.parts.frontWiperPart, testConstants.parts.rearWiperPart],
|
||||||
testConstants.parts.frontWiperPart,
|
rainDefenseResponse: testConstants.parts.rainDefensePart,
|
||||||
testConstants.parts.rearWiperPart,
|
|
||||||
testConstants.parts.rainDefensePart,
|
|
||||||
],
|
|
||||||
damage: {
|
damage: {
|
||||||
isRepair: false,
|
isRepair: false,
|
||||||
glassToReplace: [testConstants.damages.frontWindshield],
|
glassToReplace: [testConstants.damages.frontWindshield],
|
||||||
|
|
@ -142,11 +139,8 @@ const figmaScenarios = [
|
||||||
{
|
{
|
||||||
name: "05_01_CSR_Quote_Standard_Repair",
|
name: "05_01_CSR_Quote_Standard_Repair",
|
||||||
params: {
|
params: {
|
||||||
availableVaps: [
|
wiperResponse: [testConstants.parts.frontWiperPart, testConstants.parts.rearWiperPart],
|
||||||
testConstants.parts.frontWiperPart,
|
rainDefenseResponse: testConstants.parts.rainDefensePart,
|
||||||
testConstants.parts.rearWiperPart,
|
|
||||||
testConstants.parts.rainDefensePart,
|
|
||||||
],
|
|
||||||
damage: {
|
damage: {
|
||||||
isRepair: true,
|
isRepair: true,
|
||||||
glassToReplace: [],
|
glassToReplace: [],
|
||||||
|
|
@ -206,11 +200,8 @@ const figmaScenarios = [
|
||||||
{
|
{
|
||||||
name: "05_01_CSR_Quote_Recal",
|
name: "05_01_CSR_Quote_Recal",
|
||||||
params: {
|
params: {
|
||||||
availableVaps: [
|
wiperResponse: [testConstants.parts.frontWiperPart, testConstants.parts.rearWiperPart],
|
||||||
testConstants.parts.frontWiperPart,
|
rainDefenseResponse: testConstants.parts.rainDefensePart,
|
||||||
testConstants.parts.rearWiperPart,
|
|
||||||
testConstants.parts.rainDefensePart,
|
|
||||||
],
|
|
||||||
damage: {
|
damage: {
|
||||||
isRepair: false,
|
isRepair: false,
|
||||||
glassToReplace: [testConstants.damages.frontWindshield],
|
glassToReplace: [testConstants.damages.frontWindshield],
|
||||||
|
|
@ -271,11 +262,8 @@ const figmaScenarios = [
|
||||||
{
|
{
|
||||||
name: "05_01_CSR_Quote_RearGlass+NonWindshield",
|
name: "05_01_CSR_Quote_RearGlass+NonWindshield",
|
||||||
params: {
|
params: {
|
||||||
availableVaps: [
|
wiperResponse: [testConstants.parts.frontWiperPart, testConstants.parts.rearWiperPart],
|
||||||
testConstants.parts.frontWiperPart,
|
rainDefenseResponse: testConstants.parts.rainDefensePart,
|
||||||
testConstants.parts.rearWiperPart,
|
|
||||||
testConstants.parts.rainDefensePart,
|
|
||||||
],
|
|
||||||
damage: {
|
damage: {
|
||||||
isRepair: false,
|
isRepair: false,
|
||||||
glassToReplace: [testConstants.damages.rearWindshield],
|
glassToReplace: [testConstants.damages.rearWindshield],
|
||||||
|
|
@ -343,11 +331,8 @@ const figmaScenarios = [
|
||||||
{
|
{
|
||||||
name: "05_01_CSR_Quote_RearGlass+Windshield",
|
name: "05_01_CSR_Quote_RearGlass+Windshield",
|
||||||
params: {
|
params: {
|
||||||
availableVaps: [
|
wiperResponse: [testConstants.parts.frontWiperPart, testConstants.parts.rearWiperPart],
|
||||||
testConstants.parts.frontWiperPart,
|
rainDefenseResponse: testConstants.parts.rainDefensePart,
|
||||||
testConstants.parts.rearWiperPart,
|
|
||||||
testConstants.parts.rainDefensePart,
|
|
||||||
],
|
|
||||||
damage: {
|
damage: {
|
||||||
isRepair: false,
|
isRepair: false,
|
||||||
glassToReplace: [
|
glassToReplace: [
|
||||||
|
|
@ -461,7 +446,8 @@ const figmaScenarios = [
|
||||||
{
|
{
|
||||||
name: "05_01_CSR_Quote_RearGlassNoFrontFit",
|
name: "05_01_CSR_Quote_RearGlassNoFrontFit",
|
||||||
params: {
|
params: {
|
||||||
availableVaps: [testConstants.parts.rearWiperPart, testConstants.parts.rainDefensePart],
|
wiperResponse: [testConstants.parts.rearWiperPart],
|
||||||
|
rainDefenseResponse: testConstants.parts.rainDefensePart,
|
||||||
damage: {
|
damage: {
|
||||||
isRepair: false,
|
isRepair: false,
|
||||||
glassToReplace: [testConstants.damages.rearWindshield],
|
glassToReplace: [testConstants.damages.rearWindshield],
|
||||||
|
|
@ -518,11 +504,8 @@ const figmaScenarios = [
|
||||||
{
|
{
|
||||||
name: "05_01_CSR_Quote_Windshield+SideGlass",
|
name: "05_01_CSR_Quote_Windshield+SideGlass",
|
||||||
params: {
|
params: {
|
||||||
availableVaps: [
|
wiperResponse: [testConstants.parts.frontWiperPart, testConstants.parts.rearWiperPart],
|
||||||
testConstants.parts.frontWiperPart,
|
rainDefenseResponse: testConstants.parts.rainDefensePart,
|
||||||
testConstants.parts.rearWiperPart,
|
|
||||||
testConstants.parts.rainDefensePart,
|
|
||||||
],
|
|
||||||
damage: {
|
damage: {
|
||||||
isRepair: false,
|
isRepair: false,
|
||||||
glassToReplace: [
|
glassToReplace: [
|
||||||
|
|
@ -586,11 +569,8 @@ const figmaScenarios = [
|
||||||
{
|
{
|
||||||
name: "05_01_CSR_Quote_SideGlass",
|
name: "05_01_CSR_Quote_SideGlass",
|
||||||
params: {
|
params: {
|
||||||
availableVaps: [
|
wiperResponse: [testConstants.parts.frontWiperPart, testConstants.parts.rearWiperPart],
|
||||||
testConstants.parts.frontWiperPart,
|
rainDefenseResponse: testConstants.parts.rainDefensePart,
|
||||||
testConstants.parts.rearWiperPart,
|
|
||||||
testConstants.parts.rainDefensePart,
|
|
||||||
],
|
|
||||||
damage: {
|
damage: {
|
||||||
isRepair: false,
|
isRepair: false,
|
||||||
glassToReplace: [testConstants.damages.sideGlass],
|
glassToReplace: [testConstants.damages.sideGlass],
|
||||||
|
|
@ -678,7 +658,8 @@ const figmaScenarios = [
|
||||||
{
|
{
|
||||||
name: "05_01_CSR_Quote_NoWiperFit",
|
name: "05_01_CSR_Quote_NoWiperFit",
|
||||||
params: {
|
params: {
|
||||||
availableVaps: [testConstants.parts.rainDefensePart],
|
wiperResponse: [],
|
||||||
|
rainDefenseResponse: testConstants.parts.rainDefensePart,
|
||||||
damage: {
|
damage: {
|
||||||
isRepair: false,
|
isRepair: false,
|
||||||
glassToReplace: [testConstants.damages.frontWindshield],
|
glassToReplace: [testConstants.damages.frontWindshield],
|
||||||
|
|
@ -821,6 +802,8 @@ describe("Service Package Review Block", () => {
|
||||||
propsData: props,
|
propsData: props,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
initializeWithDefault(wrapper);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await wrapper.vm.$nextTick();
|
await wrapper.vm.$nextTick();
|
||||||
|
|
||||||
|
|
@ -851,6 +834,8 @@ describe("Service Package Review Block", () => {
|
||||||
propsData: props,
|
propsData: props,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
initializeWithDefault(wrapper);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await wrapper.vm.$nextTick();
|
await wrapper.vm.$nextTick();
|
||||||
|
|
||||||
|
|
@ -874,6 +859,8 @@ describe("Service Package Review Block", () => {
|
||||||
// Act
|
// Act
|
||||||
await wrapper.vm.$nextTick();
|
await wrapper.vm.$nextTick();
|
||||||
|
|
||||||
|
initializeWithDefault(wrapper);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
const includesFrontWiperCopy = wrapper.vm.displayContent.includes(
|
const includesFrontWiperCopy = wrapper.vm.displayContent.includes(
|
||||||
testConstants.vapsCopy.frontWiperCopy
|
testConstants.vapsCopy.frontWiperCopy
|
||||||
|
|
@ -893,6 +880,8 @@ describe("Service Package Review Block", () => {
|
||||||
propsData: generateDefaultProps(),
|
propsData: generateDefaultProps(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
initializeWithDefault(wrapper);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await wrapper.vm.$nextTick();
|
await wrapper.vm.$nextTick();
|
||||||
|
|
||||||
|
|
@ -908,7 +897,6 @@ describe("Service Package Review Block", () => {
|
||||||
it(`Should match figma scenario "${scenario.name}", iteration "${iteration.name}"`, async () => {
|
it(`Should match figma scenario "${scenario.name}", iteration "${iteration.name}"`, async () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
let props = generateDefaultProps();
|
let props = generateDefaultProps();
|
||||||
props.availableVaps = scenario.params.availableVaps;
|
|
||||||
props.damage = scenario.params.damage;
|
props.damage = scenario.params.damage;
|
||||||
props.glassParts = scenario.params.glassParts;
|
props.glassParts = scenario.params.glassParts;
|
||||||
props.lineItems.supportingItems = scenario.params.supportingItems;
|
props.lineItems.supportingItems = scenario.params.supportingItems;
|
||||||
|
|
@ -918,6 +906,11 @@ describe("Service Package Review Block", () => {
|
||||||
propsData: props,
|
propsData: props,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
wrapper.vm.initializeComponent({
|
||||||
|
wipers: scenario.params.wiperResponse,
|
||||||
|
rainDefense: scenario.params.rainDefenseResponse,
|
||||||
|
});
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await wrapper.vm.$nextTick();
|
await wrapper.vm.$nextTick();
|
||||||
|
|
||||||
|
|
@ -932,12 +925,18 @@ describe("Service Package Review Block", () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function initializeWithDefault(wrapper) {
|
||||||
|
wrapper.vm.initializeComponent({
|
||||||
|
wipers: [testConstants.parts.frontWiperPart],
|
||||||
|
rainDefense: testConstants.parts.rainDefensePart,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function generateDefaultProps() {
|
function generateDefaultProps() {
|
||||||
return {
|
return {
|
||||||
servicePackageOptionsCmsName: testConstants.cmsPropValues.servicePackageOptionsCmsName,
|
servicePackageOptionsCmsName: testConstants.cmsPropValues.servicePackageOptionsCmsName,
|
||||||
defaultPackageItemsCmsName: testConstants.cmsPropValues.defaultPackageItemsCmsName,
|
defaultPackageItemsCmsName: testConstants.cmsPropValues.defaultPackageItemsCmsName,
|
||||||
vapsItemsCmsName: testConstants.cmsPropValues.vapsItemsCmsName,
|
vapsItemsCmsName: testConstants.cmsPropValues.vapsItemsCmsName,
|
||||||
availableVaps: [testConstants.parts.frontWiperPart, testConstants.parts.rainDefensePart],
|
|
||||||
lineItems: {
|
lineItems: {
|
||||||
glassParts: [],
|
glassParts: [],
|
||||||
supportingItems: [],
|
supportingItems: [],
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,9 @@ import {
|
||||||
getHighestFullySatisfiedTier,
|
getHighestFullySatisfiedTier,
|
||||||
containsLineItemWithPartType,
|
containsLineItemWithPartType,
|
||||||
} from "@/helpers/service-package-helper";
|
} from "@/helpers/service-package-helper";
|
||||||
|
import { settleAllPromises } from "@/helpers/layout-helper";
|
||||||
|
import baseMixin from "@/mixins/base-mixin.js";
|
||||||
|
import { storeActions } from "@/constants/store-actions";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "service-package-review",
|
name: "service-package-review",
|
||||||
|
|
@ -18,14 +21,39 @@ export default {
|
||||||
servicePackageOptionsCmsName: String,
|
servicePackageOptionsCmsName: String,
|
||||||
defaultPackageItemsCmsName: String,
|
defaultPackageItemsCmsName: String,
|
||||||
vapsItemsCmsName: String,
|
vapsItemsCmsName: String,
|
||||||
availableVaps: Array,
|
|
||||||
lineItems: Object,
|
lineItems: Object,
|
||||||
damage: Object,
|
damage: Object,
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {};
|
return {
|
||||||
|
availableVaps: [],
|
||||||
|
};
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
loadInitialData() {
|
||||||
|
const wipersPromise = baseMixin.methods.dispatchStoreAction(storeActions.GET_WIPERS);
|
||||||
|
const rainDefensePromise = baseMixin.methods.dispatchStoreAction(
|
||||||
|
storeActions.GET_RAIN_DEFENSE
|
||||||
|
);
|
||||||
|
|
||||||
|
const promiseResultMap = [
|
||||||
|
{
|
||||||
|
resultKey: "wipers",
|
||||||
|
promise: wipersPromise,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
resultKey: "rainDefense",
|
||||||
|
promise: rainDefensePromise,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
return settleAllPromises(promiseResultMap);
|
||||||
|
},
|
||||||
|
initializeComponent(apiResponses) {
|
||||||
|
const vapsFromApi = [...apiResponses.wipers, apiResponses.rainDefense];
|
||||||
|
|
||||||
|
this.availableVaps = vapsFromApi;
|
||||||
|
},
|
||||||
editClicked() {
|
editClicked() {
|
||||||
this.$emit("edit-clicked");
|
this.$emit("edit-clicked");
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -48,19 +48,27 @@
|
||||||
|
|
||||||
<damageReview
|
<damageReview
|
||||||
cmsWidgetName="DamageReviewWidget"
|
cmsWidgetName="DamageReviewWidget"
|
||||||
|
damageLocationsWidgetName="DamageLocationsWidget"
|
||||||
:damage="damageInfo"
|
:damage="damageInfo"
|
||||||
@edit-clicked="editDamage" />
|
@edit-clicked="editDamage" />
|
||||||
|
|
||||||
<hr class="my-0" />
|
<hr class="my-0" />
|
||||||
|
|
||||||
<servicePackageReview
|
<servicePackageReview
|
||||||
|
ref="servicePackageReview"
|
||||||
servicePackageOptionsCmsName="ServicePackageTitle"
|
servicePackageOptionsCmsName="ServicePackageTitle"
|
||||||
defaultPackageItemsCmsName="DefaultPackageItemDescriptions"
|
defaultPackageItemsCmsName="DefaultPackageItemDescriptions"
|
||||||
vapsItemsCmsName="VapsItemDescriptions"
|
vapsItemsCmsName="VapsItemDescriptions"
|
||||||
:damage="damageInfo"
|
:damage="damageInfo"
|
||||||
:availableVaps="availableVaps"
|
|
||||||
:lineItems="lineItems"
|
:lineItems="lineItems"
|
||||||
@edit-clicked="editServicePackage" />
|
@edit-clicked="editServicePackage" />
|
||||||
|
|
||||||
|
<hr class="my-0" />
|
||||||
|
|
||||||
|
<serviceLocationReview
|
||||||
|
cmsWidgetName="ServiceLocationTitleWidget"
|
||||||
|
:serviceLocation="serviceLocationInfo"
|
||||||
|
@edit-clicked="editServiceLocation" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
|
|
@ -85,6 +93,7 @@ import textBlock from "@/digital-components/text-block/text-block";
|
||||||
import vehicleReview from "@/layouts/review/review-sections/vehicle-review/vehicle-review";
|
import vehicleReview from "@/layouts/review/review-sections/vehicle-review/vehicle-review";
|
||||||
import damageReview from "@/layouts/review/review-sections/damage-review/damage-review";
|
import damageReview from "@/layouts/review/review-sections/damage-review/damage-review";
|
||||||
import servicePackageReview from "@/layouts/review/review-sections/service-package-review/service-package-review";
|
import servicePackageReview from "@/layouts/review/review-sections/service-package-review/service-package-review";
|
||||||
|
import serviceLocationReview from "@/layouts/review/review-sections/service-location-review/service-location-review";
|
||||||
|
|
||||||
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
|
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
|
||||||
import { settleAllPromises } from "@/helpers/layout-helper";
|
import { settleAllPromises } from "@/helpers/layout-helper";
|
||||||
|
|
@ -102,6 +111,8 @@ export default {
|
||||||
storeActions.GET_RAIN_DEFENSE
|
storeActions.GET_RAIN_DEFENSE
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const servicePackageInitialDataPromise = servicePackageReview.methods.loadInitialData();
|
||||||
|
|
||||||
// Settle promises and get results
|
// Settle promises and get results
|
||||||
const promiseResultMap = [
|
const promiseResultMap = [
|
||||||
{
|
{
|
||||||
|
|
@ -109,12 +120,8 @@ export default {
|
||||||
promise: cmsContentPromise,
|
promise: cmsContentPromise,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
resultKey: "wipers",
|
resultKey: "servicePackageData",
|
||||||
promise: wipersPromise,
|
promise: servicePackageInitialDataPromise,
|
||||||
},
|
|
||||||
{
|
|
||||||
resultKey: "rainDefense",
|
|
||||||
promise: rainDefensePromise,
|
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
@ -123,21 +130,19 @@ export default {
|
||||||
next((vm) => {
|
next((vm) => {
|
||||||
vm.setCmsContent(resultMap.cmsContent);
|
vm.setCmsContent(resultMap.cmsContent);
|
||||||
|
|
||||||
vm.availableWipers = resultMap.wipers;
|
vm.$refs.servicePackageReview.initializeComponent(resultMap.servicePackageData);
|
||||||
vm.availableRainDefense = [resultMap.rainDefense];
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {};
|
||||||
availableWipers: null,
|
|
||||||
availableRainDefense: null,
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
arePagePrerequisitesValid() {
|
arePagePrerequisitesValid() {
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
backButtonAction() {},
|
backButtonAction() {
|
||||||
|
this.$router.navigateWithoutSaving(this.navigationScenarios.CLICKED_BACK, this.$route);
|
||||||
|
},
|
||||||
forwardButtonAction() {},
|
forwardButtonAction() {},
|
||||||
editVehicle() {
|
editVehicle() {
|
||||||
this.$router.navigateWithoutSaving(
|
this.$router.navigateWithoutSaving(
|
||||||
|
|
@ -157,6 +162,12 @@ export default {
|
||||||
this.$route
|
this.$route
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
editServiceLocation() {
|
||||||
|
this.$router.navigateWithoutSaving(
|
||||||
|
this.navigationScenarios.CLICKED_SERVICE_LOCATION_EDIT,
|
||||||
|
this.$route
|
||||||
|
);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
subHeaderTitle() {
|
subHeaderTitle() {
|
||||||
|
|
@ -174,12 +185,12 @@ export default {
|
||||||
damageInfo() {
|
damageInfo() {
|
||||||
return this.$store.getters.damage;
|
return this.$store.getters.damage;
|
||||||
},
|
},
|
||||||
availableVaps() {
|
|
||||||
return [...(this.availableWipers ?? []), ...(this.availableRainDefense ?? [])];
|
|
||||||
},
|
|
||||||
lineItems() {
|
lineItems() {
|
||||||
return this.$store.getters.lineItems;
|
return this.$store.getters.lineItems;
|
||||||
},
|
},
|
||||||
|
serviceLocationInfo() {
|
||||||
|
return this.$store.getters.order.serviceLocation;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
funnelHeader,
|
funnelHeader,
|
||||||
|
|
@ -190,6 +201,7 @@ export default {
|
||||||
vehicleReview,
|
vehicleReview,
|
||||||
damageReview,
|
damageReview,
|
||||||
servicePackageReview,
|
servicePackageReview,
|
||||||
|
serviceLocationReview,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
228
src/layouts/schedule/schedule.spec.js
Normal file
228
src/layouts/schedule/schedule.spec.js
Normal file
|
|
@ -0,0 +1,228 @@
|
||||||
|
import { shallowMount } from "@vue/test-utils";
|
||||||
|
import { getMountOptions } from "@/helpers/unit-test-helper.js";
|
||||||
|
import { applicationConfig } from "@/constants/application-config";
|
||||||
|
import { storeActions } from "@/constants/store-actions";
|
||||||
|
import schedule from "@/layouts/schedule/schedule.vue";
|
||||||
|
import store from "@/store";
|
||||||
|
import * as navigateToHeritage from "@/helpers/heritage-integration/navigation-helper";
|
||||||
|
import { nextTick } from "vue";
|
||||||
|
|
||||||
|
jest.mock("@/store", () => ({
|
||||||
|
commit: jest.fn(),
|
||||||
|
dispatch: jest.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Mock fetchCmsContentForPage
|
||||||
|
jest.mock("@/helpers/cms-content-helper", () => ({
|
||||||
|
fetchCmsContentForPage: () => Promise.resolve("content"),
|
||||||
|
splitCopyOnCMSPlaceHolder: jest.fn(() => ["A", "B"]),
|
||||||
|
}));
|
||||||
|
|
||||||
|
jest.mock(
|
||||||
|
"@/store",
|
||||||
|
() => {
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
{ virtual: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
store.getters = {
|
||||||
|
order: {
|
||||||
|
schedule: {
|
||||||
|
date: "2020-01-01",
|
||||||
|
},
|
||||||
|
lineItems: {
|
||||||
|
glassParts: [],
|
||||||
|
supportingItems: [],
|
||||||
|
},
|
||||||
|
serviceLocation: {
|
||||||
|
appointmentType: "Inshop",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
lineItems: {
|
||||||
|
glassParts: [],
|
||||||
|
supportingItems: [],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
describe("schedule.vue", () => {
|
||||||
|
test("Should navigateWithoutSaving", async () => {
|
||||||
|
//Arrange
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
customMountOptions: {
|
||||||
|
router: {
|
||||||
|
navigateWithoutSaving: jest.fn(),
|
||||||
|
},
|
||||||
|
route: { schedule },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
wrapper.vm.dispatchStoreAction = jest.fn(() => {
|
||||||
|
return {
|
||||||
|
data: [],
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
//Act
|
||||||
|
await wrapper.vm.forwardButtonAction();
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
expect(wrapper.vm.$router.navigateWithoutSaving).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
test("should pass arePagePrerequisitesValid with a mobile order and no providerNumber", () => {
|
||||||
|
//Arrange
|
||||||
|
const { wrapper } = setupMocks({});
|
||||||
|
store.getters = {
|
||||||
|
order: {
|
||||||
|
schedule: {
|
||||||
|
date: "2020-01-01",
|
||||||
|
},
|
||||||
|
serviceLocation: {
|
||||||
|
zipCode: "12345",
|
||||||
|
zipCodeCtu: "value",
|
||||||
|
appointmentType: "Mobile",
|
||||||
|
},
|
||||||
|
damage: {
|
||||||
|
isRepair: true,
|
||||||
|
},
|
||||||
|
referralNumber: "1234567",
|
||||||
|
},
|
||||||
|
payment: {
|
||||||
|
isInsurance: true,
|
||||||
|
},
|
||||||
|
lineItems: {
|
||||||
|
supportingItems: [],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid();
|
||||||
|
|
||||||
|
expect(arePagePrerequisitesValid).toBe(true);
|
||||||
|
});
|
||||||
|
test("should pass arePagePrerequisitesValid with a inshop order and providerNumber", () => {
|
||||||
|
//Arrange
|
||||||
|
const { wrapper } = setupMocks({});
|
||||||
|
store.getters = {
|
||||||
|
order: {
|
||||||
|
schedule: {
|
||||||
|
date: "2020-01-01",
|
||||||
|
},
|
||||||
|
serviceLocation: {
|
||||||
|
zipCode: "12345",
|
||||||
|
zipCodeCtu: "value",
|
||||||
|
appointmentType: "Inshop",
|
||||||
|
provider: {
|
||||||
|
providerNumber: "5",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
damage: {
|
||||||
|
isRepair: true,
|
||||||
|
},
|
||||||
|
referralNumber: "1234567",
|
||||||
|
},
|
||||||
|
payment: {
|
||||||
|
isInsurance: true,
|
||||||
|
},
|
||||||
|
lineItems: {
|
||||||
|
supportingItems: [],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid();
|
||||||
|
|
||||||
|
expect(arePagePrerequisitesValid).toBe(true);
|
||||||
|
});
|
||||||
|
test("should fail arePagePrerequisitesValid with a replace with no glass parts", () => {
|
||||||
|
//Arrange
|
||||||
|
const { wrapper } = setupMocks({});
|
||||||
|
store.getters = {
|
||||||
|
order: {
|
||||||
|
schedule: {
|
||||||
|
date: "2020-01-01",
|
||||||
|
},
|
||||||
|
serviceLocation: {
|
||||||
|
zipCode: "12345",
|
||||||
|
zipCodeCtu: "value",
|
||||||
|
appointmentType: "Inshop",
|
||||||
|
provider: {
|
||||||
|
providerNumber: "5",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
damage: {
|
||||||
|
isRepair: false,
|
||||||
|
},
|
||||||
|
referralNumber: "1234567",
|
||||||
|
},
|
||||||
|
payment: {
|
||||||
|
isInsurance: true,
|
||||||
|
},
|
||||||
|
lineItems: {
|
||||||
|
supportingItems: [],
|
||||||
|
glassParts: [],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid();
|
||||||
|
|
||||||
|
expect(arePagePrerequisitesValid).toBe(false);
|
||||||
|
});
|
||||||
|
test("should fail arePagePrerequisitesValid without isInsurance", () => {
|
||||||
|
//Arrange
|
||||||
|
const { wrapper } = setupMocks({});
|
||||||
|
store.getters = {
|
||||||
|
order: {
|
||||||
|
schedule: {
|
||||||
|
date: "2020-01-01",
|
||||||
|
},
|
||||||
|
serviceLocation: {
|
||||||
|
zipCode: "12345",
|
||||||
|
zipCodeCtu: "value",
|
||||||
|
appointmentType: "Inshop",
|
||||||
|
provider: {
|
||||||
|
providerNumber: "5",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
damage: {
|
||||||
|
isRepair: true,
|
||||||
|
},
|
||||||
|
referralNumber: "1234567",
|
||||||
|
},
|
||||||
|
payment: {
|
||||||
|
isInsurance: null,
|
||||||
|
},
|
||||||
|
lineItems: {
|
||||||
|
supportingItems: [],
|
||||||
|
glassParts: [],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid();
|
||||||
|
|
||||||
|
expect(arePagePrerequisitesValid).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const mockCmsContent = {};
|
||||||
|
|
||||||
|
function setupMocks({ customMountOptions }) {
|
||||||
|
const mountOptions = getMountOptions({
|
||||||
|
...customMountOptions,
|
||||||
|
});
|
||||||
|
|
||||||
|
mountOptions.global.mocks["$store"] = store;
|
||||||
|
mountOptions["attachTo"] = document.body;
|
||||||
|
mountOptions.mixins = [
|
||||||
|
{
|
||||||
|
methods: {
|
||||||
|
getCmsContent: jest.fn().mockImplementation((widgetName, fieldName) => {
|
||||||
|
if (mockCmsContent[widgetName] && mockCmsContent[widgetName][fieldName])
|
||||||
|
return mockCmsContent[widgetName][fieldName];
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const wrapper = shallowMount(schedule, mountOptions);
|
||||||
|
wrapper.vm.setCmsContent = jest.fn();
|
||||||
|
return { wrapper };
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,712 @@
|
||||||
|
import { shallowMount, flushPromises } from "@vue/test-utils";
|
||||||
|
import { getMountOptions } from "@/helpers/unit-test-helper.js";
|
||||||
|
import timeSlotModalQuestion from "@/layouts/schedule/time-slot-modal-question/time-slot-modal-question.vue";
|
||||||
|
import store from "@/store";
|
||||||
|
import {
|
||||||
|
RouteCodeFlags,
|
||||||
|
PREMIUM_TIME_SLOT_ID_FLAG,
|
||||||
|
PREMIUM_FEE_PART_TYPE,
|
||||||
|
} from "@/constants/schedule-constants";
|
||||||
|
|
||||||
|
describe("time-slot-modal-list-button-question.vue", () => {
|
||||||
|
test("When selected time slot is changed, a correctly formatted selectedTimeSlot should be emitted", async () => {
|
||||||
|
//Arrange
|
||||||
|
const date = "2023-07-01";
|
||||||
|
const timeSlotId = "testRouteCodeId";
|
||||||
|
const startTime = "8:00 AM";
|
||||||
|
const endTime = "8:30 AM";
|
||||||
|
const jobMaxMinutes = 100;
|
||||||
|
const expectedEmit = [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
date: date,
|
||||||
|
routeCode: timeSlotId,
|
||||||
|
startTime: startTime,
|
||||||
|
endTime: endTime,
|
||||||
|
jobMaxMinutes: jobMaxMinutes.toString(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
customMountOptions: {
|
||||||
|
propsData: {
|
||||||
|
estimatedServiceMinutesMaximum: jobMaxMinutes,
|
||||||
|
dateAndTimeSlotData: {
|
||||||
|
date: date,
|
||||||
|
timeSlots: [
|
||||||
|
{
|
||||||
|
id: timeSlotId,
|
||||||
|
startTime: startTime,
|
||||||
|
endTime: endTime,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
wrapper.vm.$refs.timeSlots.closeModal = jest.fn();
|
||||||
|
wrapper.vm.selectedTimeSlotId = timeSlotId;
|
||||||
|
|
||||||
|
//Act
|
||||||
|
wrapper.vm.setSelectedTimeSlot();
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
expect(wrapper.emitted()["update:modelValue"]).toEqual(expectedEmit);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe("time-slot-modal-list-button-question.vue Supplemental information", () => {
|
||||||
|
test("The correct supplemental information should be obtained from CMS - Mobile - Not Premium ", async () => {
|
||||||
|
//Arrange
|
||||||
|
const mobileCmsWidgetName = "MobileNotPremium";
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
customMountOptions: {
|
||||||
|
propsData: {
|
||||||
|
modelValue: { routeCode: "test" },
|
||||||
|
appointmentType: "Mobile",
|
||||||
|
mobileCmsWidgetName: mobileCmsWidgetName,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
//Assert
|
||||||
|
expect(wrapper.vm.supplementalInformationBlock).toEqual(
|
||||||
|
mockCmsContent[mobileCmsWidgetName]["BodyText"]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
test("The correct supplemental information should be obtained from CMS - Mobile - Premium", async () => {
|
||||||
|
//Arrange
|
||||||
|
const mobileCmsWidgetName = "MobilePremium";
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
customMountOptions: {
|
||||||
|
propsData: {
|
||||||
|
modelValue: { routeCode: "test" + PREMIUM_TIME_SLOT_ID_FLAG },
|
||||||
|
appointmentType: "Mobile",
|
||||||
|
mobileCmsWidgetName: mobileCmsWidgetName,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
//Assert
|
||||||
|
expect(wrapper.vm.supplementalInformationBlock).toEqual(
|
||||||
|
mockCmsContent[mobileCmsWidgetName]["BodyText"]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
test("No supplemental information should be obtained from CMS - Inshop", async () => {
|
||||||
|
//Arrange
|
||||||
|
const inshopWidgetName = "Inshop";
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
customMountOptions: {
|
||||||
|
propsData: {
|
||||||
|
modelValue: { routeCode: "test" },
|
||||||
|
appointmentType: "Inshop",
|
||||||
|
cmsWidgetName: inshopWidgetName,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
//Assert
|
||||||
|
expect(wrapper.vm.supplementalInformationBlock).toBeNull();
|
||||||
|
});
|
||||||
|
test("No supplemental information should be obtained from CMS - Drop off, nothing selected", async () => {
|
||||||
|
//Arrange
|
||||||
|
const dropOffWidgetName = "Dropoff";
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
customMountOptions: {
|
||||||
|
propsData: {
|
||||||
|
modelValue: null,
|
||||||
|
appointmentType: "Dropoff",
|
||||||
|
cmsWidgetName: dropOffWidgetName,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
//Assert
|
||||||
|
expect(wrapper.vm.supplementalInformationBlock).toBeNull();
|
||||||
|
});
|
||||||
|
test("Correct supplemental information should be retrieved, Dropoff regular", async () => {
|
||||||
|
//Arrange
|
||||||
|
const dropOffWidgetName = "Dropoff";
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
customMountOptions: {
|
||||||
|
propsData: {
|
||||||
|
modelValue: { routeCode: "Test" + RouteCodeFlags.ALL_DAY_DROP_OFF },
|
||||||
|
appointmentType: "Dropoff",
|
||||||
|
dropoffCmsWidgetName: dropOffWidgetName,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
//Assert
|
||||||
|
expect(wrapper.vm.supplementalInformationBlock).toEqual(
|
||||||
|
mockCmsContent[dropOffWidgetName]["BodyText"]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
test("Correct supplemental information should be retrieved, Dropoff Overnight", async () => {
|
||||||
|
//Arrange
|
||||||
|
const overnightDropOffCmsWidgetName = "Overnight";
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
customMountOptions: {
|
||||||
|
propsData: {
|
||||||
|
modelValue: { routeCode: "Test" + RouteCodeFlags.OVERNIGHT_DROP_OFF },
|
||||||
|
appointmentType: "Dropoff",
|
||||||
|
overnightDropOffCmsWidgetName: overnightDropOffCmsWidgetName,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
//Assert
|
||||||
|
expect(wrapper.vm.supplementalInformationBlock).toEqual(
|
||||||
|
mockCmsContent[overnightDropOffCmsWidgetName]["BodyText"]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
test("Correct supplemental information should be retrieved, Dropoff Sameday", async () => {
|
||||||
|
//Arrange
|
||||||
|
const sameDayDropOffCmsWidgetName = "Sameday";
|
||||||
|
const date = new Date().toISOString().split("T")[0];
|
||||||
|
const timeSlotId = "testRouteCodeId";
|
||||||
|
const startTime = "8:00 AM";
|
||||||
|
const endTime = "8:30 AM";
|
||||||
|
const jobMaxMinutes = 100;
|
||||||
|
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
customMountOptions: {
|
||||||
|
propsData: {
|
||||||
|
estimatedServiceMinutesMaximum: jobMaxMinutes,
|
||||||
|
dateAndTimeSlotData: {
|
||||||
|
date: date,
|
||||||
|
timeSlots: [
|
||||||
|
{
|
||||||
|
id: timeSlotId,
|
||||||
|
startTime: startTime,
|
||||||
|
endTime: endTime,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
modelValue: { routeCode: "Test" + RouteCodeFlags.ALL_DAY_DROP_OFF },
|
||||||
|
appointmentType: "Dropoff",
|
||||||
|
sameDayDropOffCmsWidgetName: sameDayDropOffCmsWidgetName,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
expect(wrapper.vm.supplementalInformationBlock).toEqual(
|
||||||
|
mockCmsContent[sameDayDropOffCmsWidgetName]["BodyText"]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("time-slot-modal-list-button-question.vue Disclaimer", () => {
|
||||||
|
test("The correct disclaimer information should be obtained from CMS - Dropoff - Sameday ", async () => {
|
||||||
|
//Arrange
|
||||||
|
const sameDayDropOffCmsWidgetName = "Sameday";
|
||||||
|
const date = new Date().toISOString().split("T")[0];
|
||||||
|
const timeSlotId = "testRouteCodeId";
|
||||||
|
const startTime = "8:00 AM";
|
||||||
|
const endTime = "8:30 AM";
|
||||||
|
const jobMaxMinutes = 100;
|
||||||
|
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
customMountOptions: {
|
||||||
|
propsData: {
|
||||||
|
estimatedServiceMinutesMaximum: jobMaxMinutes,
|
||||||
|
dateAndTimeSlotData: {
|
||||||
|
date: date,
|
||||||
|
timeSlots: [
|
||||||
|
{
|
||||||
|
id: timeSlotId,
|
||||||
|
startTime: startTime,
|
||||||
|
endTime: endTime,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
modelValue: { routeCode: "Test" + RouteCodeFlags.ALL_DAY_DROP_OFF },
|
||||||
|
appointmentType: "Dropoff",
|
||||||
|
sameDayDropOffCmsWidgetName: sameDayDropOffCmsWidgetName,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
expect(wrapper.vm.disclaimerTextBlockCopy).toEqual(
|
||||||
|
mockCmsContent[sameDayDropOffCmsWidgetName]["FooterText"]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
test("Correct disclaimer information should be retrieved, Dropoff regular", async () => {
|
||||||
|
//Arrange
|
||||||
|
const dropOffWidgetName = "Dropoff";
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
customMountOptions: {
|
||||||
|
propsData: {
|
||||||
|
modelValue: { routeCode: "Test" + RouteCodeFlags.ALL_DAY_DROP_OFF },
|
||||||
|
appointmentType: "Dropoff",
|
||||||
|
dropoffCmsWidgetName: dropOffWidgetName,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
//Assert
|
||||||
|
expect(wrapper.vm.disclaimerTextBlockCopy).toEqual(
|
||||||
|
mockCmsContent[dropOffWidgetName]["FooterText"]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
test("Correct disclaimer information should be retrieved, Dropoff overnight", async () => {
|
||||||
|
//Arrange
|
||||||
|
const overnightDropOffCmsWidgetName = "Overnight";
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
customMountOptions: {
|
||||||
|
propsData: {
|
||||||
|
modelValue: { routeCode: "Test" + RouteCodeFlags.OVERNIGHT_DROP_OFF },
|
||||||
|
appointmentType: "Dropoff",
|
||||||
|
overnightDropOffCmsWidgetName: overnightDropOffCmsWidgetName,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
//Assert
|
||||||
|
expect(wrapper.vm.disclaimerTextBlockCopy).toEqual(
|
||||||
|
mockCmsContent[overnightDropOffCmsWidgetName]["FooterText"]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
test("No disclaimer information should be retrieved, non-dropoff", async () => {
|
||||||
|
//Arrange
|
||||||
|
const inshopWidgetName = "Inshop";
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
customMountOptions: {
|
||||||
|
propsData: {
|
||||||
|
modelValue: { routeCode: "test" },
|
||||||
|
appointmentType: "Inshop",
|
||||||
|
cmsWidgetName: inshopWidgetName,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
//Assert
|
||||||
|
expect(wrapper.vm.disclaimerTextBlockCopy).toBeNull();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("time-slot-modal-list-button-question.vue Duration", () => {
|
||||||
|
test("The correct duration information should be displayed - Dropoff - Sameday ", async () => {
|
||||||
|
//Arrange
|
||||||
|
const sameDayDropOffCmsWidgetName = "Sameday";
|
||||||
|
const date = new Date().toISOString().split("T")[0];
|
||||||
|
const timeSlotId = "testRouteCodeId";
|
||||||
|
const startTime = "8:00 AM";
|
||||||
|
const endTime = "8:30 AM";
|
||||||
|
const jobMaxMinutes = 100;
|
||||||
|
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
customMountOptions: {
|
||||||
|
propsData: {
|
||||||
|
estimatedServiceMinutesMaximum: jobMaxMinutes,
|
||||||
|
dateAndTimeSlotData: {
|
||||||
|
date: date,
|
||||||
|
timeSlots: [
|
||||||
|
{
|
||||||
|
id: timeSlotId,
|
||||||
|
startTime: startTime,
|
||||||
|
endTime: endTime,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
modelValue: { routeCode: "Test" + RouteCodeFlags.ALL_DAY_DROP_OFF },
|
||||||
|
appointmentType: "Dropoff",
|
||||||
|
sameDayDropOffCmsWidgetName: sameDayDropOffCmsWidgetName,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
expect(wrapper.vm.durationTextBlockCopy).toEqual(
|
||||||
|
mockCmsContent[sameDayDropOffCmsWidgetName]["SubheaderText"]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
test("Correct duration information should be retrieved, Dropoff overnight", async () => {
|
||||||
|
//Arrange
|
||||||
|
const overnightDropOffCmsWidgetName = "Overnight";
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
customMountOptions: {
|
||||||
|
propsData: {
|
||||||
|
modelValue: { routeCode: "Test" + RouteCodeFlags.OVERNIGHT_DROP_OFF },
|
||||||
|
appointmentType: "Dropoff",
|
||||||
|
overnightDropOffCmsWidgetName: overnightDropOffCmsWidgetName,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
//Assert
|
||||||
|
expect(wrapper.vm.durationTextBlockCopy).toEqual(
|
||||||
|
mockCmsContent[overnightDropOffCmsWidgetName]["SubheaderText"]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
test("Correct duration information should be retrieved, Dropoff", async () => {
|
||||||
|
//Arrange
|
||||||
|
const dropoffCmsWidgetName = "Dropoff";
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
customMountOptions: {
|
||||||
|
propsData: {
|
||||||
|
modelValue: { routeCode: "Test" + RouteCodeFlags.ALL_DAY_DROP_OFF },
|
||||||
|
appointmentType: "Dropoff",
|
||||||
|
dropoffCmsWidgetName: dropoffCmsWidgetName,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
//Assert
|
||||||
|
expect(wrapper.vm.durationTextBlockCopy).toEqual(
|
||||||
|
mockCmsContent[dropoffCmsWidgetName]["SubheaderText"]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
test("Correct duration information should be retrieved, Inshop - convert to hours", async () => {
|
||||||
|
//Arrange
|
||||||
|
const cmsWidgetName = "Inshop";
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
customMountOptions: {
|
||||||
|
propsData: {
|
||||||
|
estimatedServiceMinutesMaximum: 180,
|
||||||
|
estimatedServiceMinutesMinimum: 120,
|
||||||
|
modelValue: { routeCode: "Test" },
|
||||||
|
appointmentType: "Inshop",
|
||||||
|
cmsWidgetName: cmsWidgetName,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
//Assert
|
||||||
|
expect(wrapper.vm.durationTextBlockCopy).toEqual(
|
||||||
|
mockCmsContent[cmsWidgetName]["SubheaderText"] + " 2 - 3 hours"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
test("Correct duration information should be retrieved, Inshop - convert to minutes", async () => {
|
||||||
|
//Arrange
|
||||||
|
const cmsWidgetName = "Inshop";
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
customMountOptions: {
|
||||||
|
propsData: {
|
||||||
|
estimatedServiceMinutesMaximum: 90,
|
||||||
|
estimatedServiceMinutesMinimum: 60,
|
||||||
|
modelValue: { routeCode: "Test" },
|
||||||
|
appointmentType: "Inshop",
|
||||||
|
cmsWidgetName: cmsWidgetName,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
//Assert
|
||||||
|
expect(wrapper.vm.durationTextBlockCopy).toEqual(
|
||||||
|
mockCmsContent[cmsWidgetName]["SubheaderText"] + " 60 - 90 minutes"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
test("Correct duration information should be retrieved, Inshop - min = maximum time", async () => {
|
||||||
|
//Arrange
|
||||||
|
const cmsWidgetName = "Inshop";
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
customMountOptions: {
|
||||||
|
propsData: {
|
||||||
|
estimatedServiceMinutesMaximum: 240,
|
||||||
|
estimatedServiceMinutesMinimum: 240,
|
||||||
|
modelValue: { routeCode: "Test" },
|
||||||
|
appointmentType: "Inshop",
|
||||||
|
cmsWidgetName: cmsWidgetName,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
//Assert
|
||||||
|
expect(wrapper.vm.durationTextBlockCopy).toEqual(
|
||||||
|
mockCmsContent[cmsWidgetName]["SubheaderText"] + " 4 hours"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
test("No duration information should be displayed, Mobile", async () => {
|
||||||
|
//Arrange
|
||||||
|
const mobileCmsWidgetName = "Mobile";
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
customMountOptions: {
|
||||||
|
propsData: {
|
||||||
|
estimatedServiceMinutesMaximum: 240,
|
||||||
|
estimatedServiceMinutesMinimum: 240,
|
||||||
|
modelValue: { routeCode: "Test" },
|
||||||
|
appointmentType: "Mobile",
|
||||||
|
mobileCmsWidgetName: mobileCmsWidgetName,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
//Assert
|
||||||
|
expect(wrapper.vm.durationTextBlockCopy).toBeNull();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("time-slot-modal-list-button-question.vue Available Timeslots", () => {
|
||||||
|
test("Available Timeslots should be formatted correctly - Dropoff - Sameday ", async () => {
|
||||||
|
//Arrange
|
||||||
|
const sameDayDropOffCmsWidgetName = "Sameday";
|
||||||
|
const date = new Date().toISOString().split("T")[0];
|
||||||
|
const timeSlotId = "testRouteCodeId";
|
||||||
|
const startTime = "8:00 AM";
|
||||||
|
const endTime = "8:30 AM";
|
||||||
|
const jobMaxMinutes = 100;
|
||||||
|
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
customMountOptions: {
|
||||||
|
propsData: {
|
||||||
|
estimatedServiceMinutesMaximum: jobMaxMinutes,
|
||||||
|
dateAndTimeSlotData: {
|
||||||
|
date: date,
|
||||||
|
timeSlots: [
|
||||||
|
{
|
||||||
|
id: timeSlotId,
|
||||||
|
startTime: startTime,
|
||||||
|
endTime: endTime,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
appointmentType: "Dropoff",
|
||||||
|
sameDayDropOffCmsWidgetName: sameDayDropOffCmsWidgetName,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
const expectedTimeSlotObject = {
|
||||||
|
buttonLabel: mockCmsContent[sameDayDropOffCmsWidgetName]["HeaderText"],
|
||||||
|
value: timeSlotId,
|
||||||
|
};
|
||||||
|
expect(wrapper.vm.availableTimeSlots[0]).toEqual(expectedTimeSlotObject);
|
||||||
|
});
|
||||||
|
test("Available Timeslots should be formatted correctly - Dropoff - Overnight ", async () => {
|
||||||
|
//Arrange
|
||||||
|
const overnightDropOffCmsWidgetName = "Overnight";
|
||||||
|
const date = new Date().toISOString().split("T")[0];
|
||||||
|
const timeSlotId = "testRouteCodeId" + RouteCodeFlags.OVERNIGHT_DROP_OFF;
|
||||||
|
const startTime = "8:00 AM";
|
||||||
|
const endTime = "8:30 AM";
|
||||||
|
const jobMaxMinutes = 100;
|
||||||
|
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
customMountOptions: {
|
||||||
|
propsData: {
|
||||||
|
estimatedServiceMinutesMaximum: jobMaxMinutes,
|
||||||
|
dateAndTimeSlotData: {
|
||||||
|
date: date,
|
||||||
|
timeSlots: [
|
||||||
|
{
|
||||||
|
id: timeSlotId,
|
||||||
|
startTime: startTime,
|
||||||
|
endTime: endTime,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
appointmentType: "Dropoff",
|
||||||
|
overnightDropOffCmsWidgetName: overnightDropOffCmsWidgetName,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
const expectedTimeSlotObject = {
|
||||||
|
buttonLabel: mockCmsContent[overnightDropOffCmsWidgetName]["HeaderText"],
|
||||||
|
value: timeSlotId,
|
||||||
|
};
|
||||||
|
expect(wrapper.vm.availableTimeSlots[0]).toEqual(expectedTimeSlotObject);
|
||||||
|
});
|
||||||
|
test("Available Timeslots should be formatted correctly - Dropoff", async () => {
|
||||||
|
//Arrange
|
||||||
|
const dropoffCmsWidgetName = "Dropoff";
|
||||||
|
const date = "2020-01-01";
|
||||||
|
const timeSlotId = "testRouteCodeId" + RouteCodeFlags.ALL_DAY_DROP_OFF;
|
||||||
|
const startTime = "8:00 AM";
|
||||||
|
const endTime = "8:30 AM";
|
||||||
|
const jobMaxMinutes = 100;
|
||||||
|
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
customMountOptions: {
|
||||||
|
propsData: {
|
||||||
|
estimatedServiceMinutesMaximum: jobMaxMinutes,
|
||||||
|
dateAndTimeSlotData: {
|
||||||
|
date: date,
|
||||||
|
timeSlots: [
|
||||||
|
{
|
||||||
|
id: timeSlotId,
|
||||||
|
startTime: startTime,
|
||||||
|
endTime: endTime,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
appointmentType: "Dropoff",
|
||||||
|
dropoffCmsWidgetName: dropoffCmsWidgetName,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
const expectedTimeSlotObject = {
|
||||||
|
buttonLabel: mockCmsContent[dropoffCmsWidgetName]["HeaderText"],
|
||||||
|
value: timeSlotId,
|
||||||
|
};
|
||||||
|
expect(wrapper.vm.availableTimeSlots[0]).toEqual(expectedTimeSlotObject);
|
||||||
|
});
|
||||||
|
test("Available Timeslots should be formatted correctly - Mobile not premium", async () => {
|
||||||
|
//Arrange
|
||||||
|
const mobileCmsWidgetName = "MobileNotPremium";
|
||||||
|
const date = "2020-01-01";
|
||||||
|
const timeSlotId = "testRouteCodeId";
|
||||||
|
const startTime = "8:00";
|
||||||
|
const endTime = "8:30";
|
||||||
|
const jobMaxMinutes = 100;
|
||||||
|
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
customMountOptions: {
|
||||||
|
propsData: {
|
||||||
|
estimatedServiceMinutesMaximum: jobMaxMinutes,
|
||||||
|
dateAndTimeSlotData: {
|
||||||
|
date: date,
|
||||||
|
timeSlots: [
|
||||||
|
{
|
||||||
|
id: timeSlotId,
|
||||||
|
startTime: startTime,
|
||||||
|
endTime: endTime,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
appointmentType: "Mobile",
|
||||||
|
mobileCmsWidgetName: mobileCmsWidgetName,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
const expectedTimeSlotObject = {
|
||||||
|
buttonLabel: startTime + " AM - " + endTime + " AM",
|
||||||
|
value: timeSlotId,
|
||||||
|
};
|
||||||
|
expect(wrapper.vm.availableTimeSlots[0]).toEqual(expectedTimeSlotObject);
|
||||||
|
});
|
||||||
|
test("Available Timeslots should be formatted correctly - Mobile with premium", async () => {
|
||||||
|
//Arrange
|
||||||
|
const mobilePremiumCmsWidgetName = "MobilePremium";
|
||||||
|
const date = "2020-01-01";
|
||||||
|
const timeSlotId = "testRouteCodeId";
|
||||||
|
const startTime = "8:00";
|
||||||
|
const endTime = "8:30";
|
||||||
|
const jobMaxMinutes = 100;
|
||||||
|
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
customMountOptions: {
|
||||||
|
propsData: {
|
||||||
|
estimatedServiceMinutesMaximum: jobMaxMinutes,
|
||||||
|
premiumAppointmentFee: {
|
||||||
|
partType: PREMIUM_FEE_PART_TYPE,
|
||||||
|
},
|
||||||
|
dateAndTimeSlotData: {
|
||||||
|
date: date,
|
||||||
|
timeSlots: [
|
||||||
|
{
|
||||||
|
id: timeSlotId,
|
||||||
|
startTime: startTime,
|
||||||
|
endTime: endTime,
|
||||||
|
offerPremium: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
appointmentType: "Mobile",
|
||||||
|
mobilePremiumCmsWidgetName: mobilePremiumCmsWidgetName,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
const expectedTimeSlotObject = {
|
||||||
|
additionalButtonData: {
|
||||||
|
isPremiumAppointment: true,
|
||||||
|
},
|
||||||
|
buttonLabel: mockCmsContent[mobilePremiumCmsWidgetName]["HeaderText"],
|
||||||
|
buttonLabelSubCopy: "+$15.99",
|
||||||
|
value: timeSlotId + PREMIUM_TIME_SLOT_ID_FLAG,
|
||||||
|
};
|
||||||
|
expect(wrapper.vm.availableTimeSlots[0]).toEqual(expectedTimeSlotObject);
|
||||||
|
});
|
||||||
|
test("Available Timeslots should be formatted correctly - Inshop", async () => {
|
||||||
|
//Arrange
|
||||||
|
const cmsWidgetName = "Inshop";
|
||||||
|
const date = "2020-01-01";
|
||||||
|
const timeSlotId = "testRouteCodeId";
|
||||||
|
const startTime = "8:00";
|
||||||
|
const endTime = "8:30";
|
||||||
|
const jobMaxMinutes = 100;
|
||||||
|
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
customMountOptions: {
|
||||||
|
propsData: {
|
||||||
|
estimatedServiceMinutesMaximum: jobMaxMinutes,
|
||||||
|
dateAndTimeSlotData: {
|
||||||
|
date: date,
|
||||||
|
timeSlots: [
|
||||||
|
{
|
||||||
|
id: timeSlotId,
|
||||||
|
startTime: startTime,
|
||||||
|
endTime: endTime,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
appointmentType: "Inshop",
|
||||||
|
cmsWidgetName: cmsWidgetName,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
const expectedTimeSlotObject = { buttonLabel: startTime + " AM", value: timeSlotId };
|
||||||
|
expect(wrapper.vm.availableTimeSlots[0]).toEqual(expectedTimeSlotObject);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const mockCmsContent = {
|
||||||
|
MobileNotPremium: {
|
||||||
|
BodyText: "Mobile, not premium BodyText",
|
||||||
|
FooterText: "Mobile, not premium FooterText",
|
||||||
|
SubheaderText: "Mobile, not premium SubheaderText",
|
||||||
|
HeaderText: "Mobile, not premium HeaderText",
|
||||||
|
},
|
||||||
|
MobilePremium: {
|
||||||
|
"BodyText:": "Mobile, with premium BodyText",
|
||||||
|
FooterText: "Mobile, with premium FooterText",
|
||||||
|
SubheaderText: "Mobile, with premium SubheaderText",
|
||||||
|
HeaderText: "Mobile, with premium HeaderText",
|
||||||
|
},
|
||||||
|
Inshop: {
|
||||||
|
BodyText: "Inshop BodyText",
|
||||||
|
FooterText: "Inshop FooterText",
|
||||||
|
SubheaderText: "Inshop SubheaderText",
|
||||||
|
HeaderText: "Inshop HeaderText",
|
||||||
|
},
|
||||||
|
Dropoff: {
|
||||||
|
BodyText: "Dropoff BodyText",
|
||||||
|
FooterText: "Dropoff FooterText",
|
||||||
|
SubheaderText: "Dropoff SubheaderText",
|
||||||
|
HeaderText: "Dropoff HeaderText",
|
||||||
|
},
|
||||||
|
Overnight: {
|
||||||
|
BodyText: "Dropoff Overnight",
|
||||||
|
FooterText: "Dropoff, Overnight FooterText",
|
||||||
|
SubheaderText: "Dropoff, Overnight SubheaderText",
|
||||||
|
HeaderText: "Dropoff, Overnight HeaderText",
|
||||||
|
},
|
||||||
|
Sameday: {
|
||||||
|
BodyText: "Dropoff Sameday",
|
||||||
|
FooterText: "Dropoff, Sameday FooterText",
|
||||||
|
SubheaderText: "Dropoff, Sameday SubheaderText",
|
||||||
|
HeaderText: "Dropoff, Sameday HeaderText",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
function setupMocks({ customMountOptions }) {
|
||||||
|
const mountOptions = getMountOptions({
|
||||||
|
...customMountOptions,
|
||||||
|
});
|
||||||
|
mountOptions.global.mocks["$store"] = store;
|
||||||
|
mountOptions["attachTo"] = document.body;
|
||||||
|
mountOptions.mixins = [
|
||||||
|
{
|
||||||
|
methods: {
|
||||||
|
getCmsContent: jest.fn().mockImplementation((widgetName, fieldName) => {
|
||||||
|
if (mockCmsContent[widgetName] && mockCmsContent[widgetName][fieldName])
|
||||||
|
return mockCmsContent[widgetName][fieldName];
|
||||||
|
}),
|
||||||
|
getTotalLineItemPrice: jest.fn().mockImplementation(() => 15.99),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const wrapper = shallowMount(timeSlotModalQuestion, mountOptions);
|
||||||
|
wrapper.vm.setCmsContent = jest.fn();
|
||||||
|
return { wrapper };
|
||||||
|
}
|
||||||
|
|
@ -150,7 +150,7 @@ export default {
|
||||||
return this.modelValue?.routeCode;
|
return this.modelValue?.routeCode;
|
||||||
},
|
},
|
||||||
set: function (newValue) {
|
set: function (newValue) {
|
||||||
// Button Question only supports Number, or String data types so we must get the full object to emit
|
// Button Question only supports Number, or String data types so we must convert to the full object before emitting
|
||||||
this.selectedValue = this.getSelectedTimeSlotObject(newValue);
|
this.selectedValue = this.getSelectedTimeSlotObject(newValue);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -326,7 +326,7 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
modal() {
|
modal() {
|
||||||
return this.$refs["timeSlots"];
|
return this.$refs[this.modalName];
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,10 @@
|
||||||
@click-event="openModal" />
|
@click-event="openModal" />
|
||||||
</div>
|
</div>
|
||||||
<div v-show="errorMessage" class="row my-1 form-test-error">
|
<div v-show="errorMessage" class="row my-1 form-test-error">
|
||||||
<span class="d-inline-flex small mt-0 center-error-message" role="alert">
|
<span
|
||||||
|
class="d-inline-flex small mt-0 center-error-message"
|
||||||
|
aria-atomic="true"
|
||||||
|
aria-live="polite">
|
||||||
{{ errorMessage }}
|
{{ errorMessage }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,7 @@ jest.mock("@/store", () => ({
|
||||||
damage: {
|
damage: {
|
||||||
glassToReplace: [],
|
glassToReplace: [],
|
||||||
},
|
},
|
||||||
|
order: { serviceLocation: { zipCode: "11111" } },
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
@ -133,6 +134,7 @@ describe("vehicle-damage.vue", () => {
|
||||||
getters: {
|
getters: {
|
||||||
vehicle: {},
|
vehicle: {},
|
||||||
payment: { insuranceCoverage: { isVerified: false } },
|
payment: { insuranceCoverage: { isVerified: false } },
|
||||||
|
order: { serviceLocation: { zipCode: "11111" } },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -175,7 +177,7 @@ describe("vehicle-damage.vue", () => {
|
||||||
expect(wrapper.vm.selectedGlassToReplace()).toEqual(expectedGlassToReplace);
|
expect(wrapper.vm.selectedGlassToReplace()).toEqual(expectedGlassToReplace);
|
||||||
expect(baseMixin.methods.dispatchStoreAction).toBeCalledWith(
|
expect(baseMixin.methods.dispatchStoreAction).toBeCalledWith(
|
||||||
storeActions.GET_DAMAGE_OPTIONS,
|
storeActions.GET_DAMAGE_OPTIONS,
|
||||||
{ carId: "C00000000" }
|
{ carId: "C00000000", zipCode: "11111" }
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -241,6 +243,7 @@ describe("vehicle-damage.vue", () => {
|
||||||
getters: {
|
getters: {
|
||||||
vehicle: {},
|
vehicle: {},
|
||||||
payment: { insuranceCoverage: { isVerified: false } },
|
payment: { insuranceCoverage: { isVerified: false } },
|
||||||
|
order: { serviceLocation: { zipCode: "11111" } },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -270,11 +273,10 @@ describe("vehicle-damage.vue", () => {
|
||||||
expect(wrapper.vm.selectedGlassToReplace()).toEqual(expectedGlassToReplace);
|
expect(wrapper.vm.selectedGlassToReplace()).toEqual(expectedGlassToReplace);
|
||||||
expect(baseMixin.methods.dispatchStoreAction).toBeCalledWith(
|
expect(baseMixin.methods.dispatchStoreAction).toBeCalledWith(
|
||||||
storeActions.GET_DAMAGE_OPTIONS,
|
storeActions.GET_DAMAGE_OPTIONS,
|
||||||
{ carId: "C00000000" }
|
{ carId: "C00000000", zipCode: "11111" }
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("alert", () => {
|
describe("alert", () => {
|
||||||
test("when displayVehicleChangeAlert router params is true, the alert: 'vehicleChangeAlert' should be rendered", () => {
|
test("when displayVehicleChangeAlert router params is true, the alert: 'vehicleChangeAlert' should be rendered", () => {
|
||||||
// Arrange & Act
|
// Arrange & Act
|
||||||
|
|
@ -321,7 +323,6 @@ describe("vehicle-damage.vue", () => {
|
||||||
expect(wrapper.findComponent({ ref: "vehicleChangeAlert" }).exists()).toBe(false);
|
expect(wrapper.findComponent({ ref: "vehicleChangeAlert" }).exists()).toBe(false);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("glass selections and corresponding variables", () => {
|
describe("glass selections and corresponding variables", () => {
|
||||||
test("isWindshieldDamageLocation is true when windshield is selected", async () => {
|
test("isWindshieldDamageLocation is true when windshield is selected", async () => {
|
||||||
//Arrange
|
//Arrange
|
||||||
|
|
@ -453,7 +454,6 @@ describe("vehicle-damage.vue", () => {
|
||||||
expect(wrapper.vm.isPassengerSideReplace).toEqual(true);
|
expect(wrapper.vm.isPassengerSideReplace).toEqual(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("state validations", () => {
|
describe("state validations", () => {
|
||||||
test("CarId set, arePagePrerequisitesValid should be true ", async () => {
|
test("CarId set, arePagePrerequisitesValid should be true ", async () => {
|
||||||
//Arrange
|
//Arrange
|
||||||
|
|
@ -474,7 +474,6 @@ describe("vehicle-damage.vue", () => {
|
||||||
expect(arePagePrerequisitesValid).toBe(true);
|
expect(arePagePrerequisitesValid).toBe(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("input validations", () => {
|
describe("input validations", () => {
|
||||||
// THE FOLLOWING TEST IS NOT NECESSARILY REQUIRED FOR COVERAGE
|
// THE FOLLOWING TEST IS NOT NECESSARILY REQUIRED FOR COVERAGE
|
||||||
// BUT KEEP FOR AN EXAMPLE OF A VALIDATION TEST
|
// BUT KEEP FOR AN EXAMPLE OF A VALIDATION TEST
|
||||||
|
|
@ -501,7 +500,6 @@ describe("vehicle-damage.vue", () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("get glass options from store", () => {
|
describe("get glass options from store", () => {
|
||||||
const damageLocations = [
|
const damageLocations = [
|
||||||
["Windshield", [damageLocationsSelected.WINDSHIELD]],
|
["Windshield", [damageLocationsSelected.WINDSHIELD]],
|
||||||
|
|
@ -528,6 +526,7 @@ describe("vehicle-damage.vue", () => {
|
||||||
eventBusItem: jest.fn(),
|
eventBusItem: jest.fn(),
|
||||||
damage: { glassToReplace: [{ glassLocation: damageLocation }] },
|
damage: { glassToReplace: [{ glassLocation: damageLocation }] },
|
||||||
isRepair: true,
|
isRepair: true,
|
||||||
|
order: { serviceLocation: { zipCode: "11111" } },
|
||||||
};
|
};
|
||||||
|
|
||||||
var glassSelections = wrapper.vm.getDamageLocationsFromStore();
|
var glassSelections = wrapper.vm.getDamageLocationsFromStore();
|
||||||
|
|
@ -605,6 +604,7 @@ describe("vehicle-damage.vue", () => {
|
||||||
isRepair: isRepair,
|
isRepair: isRepair,
|
||||||
numberOfChips: 2,
|
numberOfChips: 2,
|
||||||
},
|
},
|
||||||
|
order: { serviceLocation: { zipCode: "11111" } },
|
||||||
};
|
};
|
||||||
|
|
||||||
var windshieldSelections = wrapper.vm.getWindshieldOptionsFromStore();
|
var windshieldSelections = wrapper.vm.getWindshieldOptionsFromStore();
|
||||||
|
|
@ -641,6 +641,7 @@ describe("vehicle-damage.vue", () => {
|
||||||
glassToReplace: [{ glassLocation: damageLocation, glassName: damageName }],
|
glassToReplace: [{ glassLocation: damageLocation, glassName: damageName }],
|
||||||
},
|
},
|
||||||
isRepair: true,
|
isRepair: true,
|
||||||
|
order: { serviceLocation: { zipCode: "11111" } },
|
||||||
};
|
};
|
||||||
|
|
||||||
var glassSelections = wrapper.vm.getDriverSideReplaceOptionsFromStore();
|
var glassSelections = wrapper.vm.getDriverSideReplaceOptionsFromStore();
|
||||||
|
|
@ -677,6 +678,7 @@ describe("vehicle-damage.vue", () => {
|
||||||
glassToReplace: [{ glassLocation: damageLocation, glassName: damageName }],
|
glassToReplace: [{ glassLocation: damageLocation, glassName: damageName }],
|
||||||
},
|
},
|
||||||
isRepair: true,
|
isRepair: true,
|
||||||
|
order: { serviceLocation: { zipCode: "11111" } },
|
||||||
};
|
};
|
||||||
|
|
||||||
var glassSelections = wrapper.vm.getPassengerSideReplaceOptionsFromStore();
|
var glassSelections = wrapper.vm.getPassengerSideReplaceOptionsFromStore();
|
||||||
|
|
@ -711,6 +713,7 @@ describe("vehicle-damage.vue", () => {
|
||||||
glassToReplace: [{ glassLocation: damageLocation, glassName: damageName }],
|
glassToReplace: [{ glassLocation: damageLocation, glassName: damageName }],
|
||||||
},
|
},
|
||||||
isRepair: true,
|
isRepair: true,
|
||||||
|
order: { serviceLocation: { zipCode: "11111" } },
|
||||||
};
|
};
|
||||||
|
|
||||||
var glassSelections = wrapper.vm.getRearReplaceOptionsFromStore();
|
var glassSelections = wrapper.vm.getRearReplaceOptionsFromStore();
|
||||||
|
|
@ -720,7 +723,6 @@ describe("vehicle-damage.vue", () => {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("hide back button", () => {
|
describe("hide back button", () => {
|
||||||
test("if claim registration is delayed => should hide back button", () => {
|
test("if claim registration is delayed => should hide back button", () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
|
|
@ -744,6 +746,7 @@ describe("vehicle-damage.vue", () => {
|
||||||
getters: {
|
getters: {
|
||||||
vehicle: {},
|
vehicle: {},
|
||||||
payment: { insuranceCoverage: { isVerified: true } },
|
payment: { insuranceCoverage: { isVerified: true } },
|
||||||
|
order: { serviceLocation: { zipCode: "11111" } },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -784,6 +787,7 @@ function setupMocks({ pageHeaderWidgetHeaderText, mountOptionsMockData, funnelCo
|
||||||
isVerified: false,
|
isVerified: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
order: { serviceLocation: { zipCode: "11111" } },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -81,7 +81,7 @@ import { getFunnelCookie } from "@/helpers/heritage-integration/cookie-helper";
|
||||||
|
|
||||||
import store from "@/store";
|
import store from "@/store";
|
||||||
import baseMixin from "@/mixins/base-mixin";
|
import baseMixin from "@/mixins/base-mixin";
|
||||||
|
import { queryStrings } from "@/constants/query-strings";
|
||||||
// DEFINE VALIDATION RULES
|
// DEFINE VALIDATION RULES
|
||||||
defineRule("replace-options-required", required(errorMessages.REPLACE_OPTIONS_REQUIRED));
|
defineRule("replace-options-required", required(errorMessages.REPLACE_OPTIONS_REQUIRED));
|
||||||
|
|
||||||
|
|
@ -90,9 +90,20 @@ export default {
|
||||||
async beforeRouteEnter(to, from, next) {
|
async beforeRouteEnter(to, from, next) {
|
||||||
// Call APIs
|
// Call APIs
|
||||||
const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage);
|
const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage);
|
||||||
|
const queryString = window.location.search;
|
||||||
|
const urlParams = new URLSearchParams(queryString);
|
||||||
|
const lowerCaseParams = new URLSearchParams();
|
||||||
|
for (const [name, value] of urlParams) {
|
||||||
|
lowerCaseParams.append(name.toLowerCase(), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
const zip = lowerCaseParams.get(queryStrings.ZIP_CODE)
|
||||||
|
? lowerCaseParams.get(queryStrings.ZIP_CODE)
|
||||||
|
: store.getters.order.serviceLocation.zipCode;
|
||||||
|
|
||||||
const damageOptionsPromise = baseMixin.methods.dispatchStoreAction(
|
const damageOptionsPromise = baseMixin.methods.dispatchStoreAction(
|
||||||
storeActions.GET_DAMAGE_OPTIONS,
|
storeActions.GET_DAMAGE_OPTIONS,
|
||||||
{ carId: store.getters.vehicle.carId }
|
{ carId: store.getters.vehicle.carId, zipCode: zip }
|
||||||
);
|
);
|
||||||
|
|
||||||
// Settle promises and get results
|
// Settle promises and get results
|
||||||
|
|
@ -135,6 +146,7 @@ export default {
|
||||||
},
|
},
|
||||||
selectedWindshieldOptions: this.getWindshieldOptionsFromStore(),
|
selectedWindshieldOptions: this.getWindshieldOptionsFromStore(),
|
||||||
selectedRearReplaceOptions: this.getRearReplaceOptionsFromStore(),
|
selectedRearReplaceOptions: this.getRearReplaceOptionsFromStore(),
|
||||||
|
serviceZipCode: this.getZipFromStore() ?? this.$route.query.zipcode,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
|
@ -157,6 +169,18 @@ export default {
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if (this.serviceZipCode) {
|
||||||
|
this.pushEventToGA(
|
||||||
|
this.GaCategories.FUNNEL_ENTRY,
|
||||||
|
this.GaActions.ZIP_CODE_PROVIDED,
|
||||||
|
this.serviceZipCode,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
getZipFromStore() {
|
||||||
|
return this.$store.getters.order.serviceLocation.zipCode;
|
||||||
},
|
},
|
||||||
|
|
||||||
backButtonAction() {
|
backButtonAction() {
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<dropdownQuestion
|
<dropdownQuestion disableAutoFill v-model="selectedValue" :valueAsKey="true" />
|
||||||
:options="values"
|
|
||||||
disableAutoFill
|
|
||||||
v-model="selectedValue"
|
|
||||||
:isDisabled="!values.length" />
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
@ -12,16 +8,8 @@ import dropdownQuestion from "@/digital-components/dropdown-question/dropdown-qu
|
||||||
export default {
|
export default {
|
||||||
name: "vehicle-question",
|
name: "vehicle-question",
|
||||||
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
values: [],
|
|
||||||
selectedIndex: null,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
modelValue: String,
|
modelValue: String,
|
||||||
updateValues: Function,
|
|
||||||
},
|
},
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
|
|
@ -30,33 +18,13 @@ export default {
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
selectedValue: {
|
selectedValue: {
|
||||||
get() {
|
get: function () {
|
||||||
return this.selectedIndex?.toString();
|
return this.modelValue?.toString();
|
||||||
},
|
},
|
||||||
set(newValue) {
|
set: function (newValue) {
|
||||||
this.selectedIndex = newValue;
|
|
||||||
newValue = newValue != null && newValue > -1 ? this.values[newValue] : null;
|
|
||||||
this.$emit("update:modelValue", newValue);
|
this.$emit("update:modelValue", newValue);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
|
||||||
async getNewValues(selectedYMMS) {
|
|
||||||
const results = await this.updateValues();
|
|
||||||
this.values = results?.data;
|
|
||||||
if (this.values.length == 1) {
|
|
||||||
this.selectedValue = 0;
|
|
||||||
} else {
|
|
||||||
this.selectedValue =
|
|
||||||
selectedYMMS != null ? this.values.indexOf(selectedYMMS) : null;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
clearValues() {
|
|
||||||
this.values = [];
|
|
||||||
this.selectedValue = null;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -15,8 +15,9 @@
|
||||||
ref="vehicleYearQuestion"
|
ref="vehicleYearQuestion"
|
||||||
class="mb-2 mt-4"
|
class="mb-2 mt-4"
|
||||||
v-model="selectedYear"
|
v-model="selectedYear"
|
||||||
|
:isDisabled="!yearOptions.length"
|
||||||
|
:options="yearOptions"
|
||||||
cmsWidgetName="VehicleYearQuestion"
|
cmsWidgetName="VehicleYearQuestion"
|
||||||
:updateValues="updateYearValues"
|
|
||||||
validationRules="year-required"
|
validationRules="year-required"
|
||||||
placeHolderText="Select year"
|
placeHolderText="Select year"
|
||||||
inputId="yearQuestionField" />
|
inputId="yearQuestionField" />
|
||||||
|
|
@ -25,8 +26,9 @@
|
||||||
ref="vehicleMakeQuestion"
|
ref="vehicleMakeQuestion"
|
||||||
class="mb-2 mt-4"
|
class="mb-2 mt-4"
|
||||||
v-model="selectedMake"
|
v-model="selectedMake"
|
||||||
|
:isDisabled="!makeOptions.length"
|
||||||
|
:options="makeOptions"
|
||||||
cmsWidgetName="VehicleMakeQuestion"
|
cmsWidgetName="VehicleMakeQuestion"
|
||||||
:updateValues="updateMakeValues"
|
|
||||||
validationRules="make-required"
|
validationRules="make-required"
|
||||||
placeHolderText="Select make"
|
placeHolderText="Select make"
|
||||||
inputId="makeQuestionField" />
|
inputId="makeQuestionField" />
|
||||||
|
|
@ -36,7 +38,8 @@
|
||||||
class="mb-2 mt-4"
|
class="mb-2 mt-4"
|
||||||
v-model="selectedModel"
|
v-model="selectedModel"
|
||||||
cmsWidgetName="VehicleModelQuestion"
|
cmsWidgetName="VehicleModelQuestion"
|
||||||
:updateValues="updateModelValues"
|
:isDisabled="!modelOptions.length"
|
||||||
|
:options="modelOptions"
|
||||||
validationRules="model-required"
|
validationRules="model-required"
|
||||||
placeHolderText="Select model"
|
placeHolderText="Select model"
|
||||||
inputId="modelQuestionField" />
|
inputId="modelQuestionField" />
|
||||||
|
|
@ -46,7 +49,8 @@
|
||||||
class="mb-2 mt-4"
|
class="mb-2 mt-4"
|
||||||
v-model="selectedStyle"
|
v-model="selectedStyle"
|
||||||
cmsWidgetName="VehicleStyleQuestion"
|
cmsWidgetName="VehicleStyleQuestion"
|
||||||
:updateValues="updateStyleValues"
|
:isDisabled="!styleOptions.length"
|
||||||
|
:options="styleOptions"
|
||||||
validationRules="style-required"
|
validationRules="style-required"
|
||||||
placeHolderText="Select style"
|
placeHolderText="Select style"
|
||||||
inputId="styleQuestionField" />
|
inputId="styleQuestionField" />
|
||||||
|
|
@ -101,10 +105,14 @@ export default {
|
||||||
name: "vehicle",
|
name: "vehicle",
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
selectedYear: null,
|
selectedYear: this.selectedYearfromStore(),
|
||||||
selectedMake: null,
|
selectedMake: this.selectedMakefromStore(),
|
||||||
selectedModel: null,
|
selectedModel: this.selectedModelfromStore(),
|
||||||
selectedStyle: null,
|
selectedStyle: this.selectedStylefromStore(),
|
||||||
|
yearOptions: [],
|
||||||
|
makeOptions: [],
|
||||||
|
modelOptions: [],
|
||||||
|
styleOptions: [],
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -113,10 +121,6 @@ export default {
|
||||||
validationRules: String,
|
validationRules: String,
|
||||||
},
|
},
|
||||||
|
|
||||||
mounted() {
|
|
||||||
this.$refs["vehicleYearQuestion"].getNewValues(this.selectedYearfromStore);
|
|
||||||
},
|
|
||||||
|
|
||||||
async beforeRouteEnter(to, from, next) {
|
async beforeRouteEnter(to, from, next) {
|
||||||
// Call APIs
|
// Call APIs
|
||||||
|
|
||||||
|
|
@ -124,6 +128,43 @@ export default {
|
||||||
const experimentForLogging = store.getters.applicationUser.experiments.find(
|
const experimentForLogging = store.getters.applicationUser.experiments.find(
|
||||||
(e) => e.universeName === experimentUniverses.CONCEPT_FUNNEL
|
(e) => e.universeName === experimentUniverses.CONCEPT_FUNNEL
|
||||||
);
|
);
|
||||||
|
const yearQuestionInitialDataPromise = baseMixin.methods.dispatchStoreAction(
|
||||||
|
storeActions.GET_VEHICLE_YEARS,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
var makeQuestionInitialDataPromise = null;
|
||||||
|
var modelQuestionInitialDataPromise = null;
|
||||||
|
var styleQuestionInitialDataPromise = null;
|
||||||
|
|
||||||
|
if (
|
||||||
|
store.getters.order.vehicle.make &&
|
||||||
|
store.getters.order.vehicle.model &&
|
||||||
|
store.getters.order.vehicle.style
|
||||||
|
) {
|
||||||
|
makeQuestionInitialDataPromise = baseMixin.methods.dispatchStoreAction(
|
||||||
|
storeActions.GET_VEHICLE_MAKES,
|
||||||
|
{
|
||||||
|
year: store.getters.order.vehicle.year,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
modelQuestionInitialDataPromise = baseMixin.methods.dispatchStoreAction(
|
||||||
|
storeActions.GET_VEHICLE_MODELS,
|
||||||
|
{
|
||||||
|
year: store.getters.order.vehicle.year,
|
||||||
|
make: store.getters.order.vehicle.make,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
styleQuestionInitialDataPromise = baseMixin.methods.dispatchStoreAction(
|
||||||
|
storeActions.GET_VEHICLE_STYLES,
|
||||||
|
{
|
||||||
|
year: store.getters.order.vehicle.year,
|
||||||
|
make: store.getters.order.vehicle.make,
|
||||||
|
model: store.getters.order.vehicle.model,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// If the concept funnel experiment is found, as it should be when coming from safelite.com, then log the experiment exposure.
|
// If the concept funnel experiment is found, as it should be when coming from safelite.com, then log the experiment exposure.
|
||||||
if (experimentForLogging !== undefined) {
|
if (experimentForLogging !== undefined) {
|
||||||
|
|
@ -146,6 +187,22 @@ export default {
|
||||||
resultKey: "cmsContent",
|
resultKey: "cmsContent",
|
||||||
promise: cmsContentPromise,
|
promise: cmsContentPromise,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
resultKey: "yearQuestionInitialData",
|
||||||
|
promise: yearQuestionInitialDataPromise,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
resultKey: "makeQuestionInitialData",
|
||||||
|
promise: makeQuestionInitialDataPromise,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
resultKey: "modelQuestionInitialData",
|
||||||
|
promise: modelQuestionInitialDataPromise,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
resultKey: "styleQuestionInitialData",
|
||||||
|
promise: styleQuestionInitialDataPromise,
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
let resultMap = await settleAllPromises(promiseResultMap);
|
let resultMap = await settleAllPromises(promiseResultMap);
|
||||||
|
|
@ -153,48 +210,74 @@ export default {
|
||||||
// Call the "next" function to complete the transition to this page.
|
// Call the "next" function to complete the transition to this page.
|
||||||
next((vm) => {
|
next((vm) => {
|
||||||
vm.setCmsContent(resultMap.cmsContent);
|
vm.setCmsContent(resultMap.cmsContent);
|
||||||
|
vm.initializeYearComponent(resultMap.yearQuestionInitialData);
|
||||||
|
|
||||||
|
if (
|
||||||
|
makeQuestionInitialDataPromise &&
|
||||||
|
modelQuestionInitialDataPromise &&
|
||||||
|
styleQuestionInitialDataPromise
|
||||||
|
)
|
||||||
|
vm.initializeMMSComponent(
|
||||||
|
resultMap.makeQuestionInitialData,
|
||||||
|
resultMap.modelQuestionInitialData,
|
||||||
|
resultMap.styleQuestionInitialData
|
||||||
|
);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
watch: {
|
watch: {
|
||||||
selectedYear(year) {
|
async selectedYear(year) {
|
||||||
const parsedYear = parseInt(year);
|
|
||||||
this.dispatchStoreAction(storeActions.SAVE_VEHICLE_YEAR, parsedYear);
|
|
||||||
if (year) {
|
if (year) {
|
||||||
this.$refs["vehicleMakeQuestion"].getNewValues(this.selectedMakefromStore);
|
const result = await this.getMakeOptions(year);
|
||||||
|
this.makeOptions = result?.data;
|
||||||
|
if (this.selectedYearfromStore() !== year) {
|
||||||
|
this.selectedMake = null;
|
||||||
|
this.selectedModel = null;
|
||||||
|
this.selectedStyle = null;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
this.$refs["vehicleMakeQuestion"].clearValues();
|
this.makeOptions = [];
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
selectedMake(make) {
|
async selectedMake(make) {
|
||||||
this.dispatchStoreAction(storeActions.SAVE_VEHICLE_MAKE, make, false);
|
|
||||||
if (make) {
|
if (make) {
|
||||||
this.$refs["vehicleModelQuestion"].getNewValues(this.selectedModelfromStore);
|
const result = await this.getModelOptions(this.selectedYear, make);
|
||||||
|
this.modelOptions = result?.data;
|
||||||
|
if (this.selectedMakefromStore() !== make) {
|
||||||
|
this.selectedModel = null;
|
||||||
|
this.selectedStyle = null;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
this.$refs["vehicleModelQuestion"].clearValues();
|
this.modelOptions = [];
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
selectedModel(model) {
|
async selectedModel(model) {
|
||||||
this.dispatchStoreAction(storeActions.SAVE_VEHICLE_MODEL, model, false);
|
|
||||||
if (model) {
|
if (model) {
|
||||||
this.$refs["vehicleStyleQuestion"].getNewValues(this.selectedStylefromStore);
|
const result = await this.getStyleOptions(
|
||||||
|
this.selectedYear,
|
||||||
|
this.selectedMake,
|
||||||
|
model
|
||||||
|
);
|
||||||
|
this.styleOptions = result?.data;
|
||||||
|
if (this.selectedModelfromStore() !== model) {
|
||||||
|
this.selectedStyle = null;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
this.$refs["vehicleStyleQuestion"].clearValues();
|
this.styleOptions = [];
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
selectedStyle(style) {
|
selectedStyle(style) {
|
||||||
this.dispatchStoreAction(storeActions.SAVE_VEHICLE_STYLE, style, false);
|
this.setVehicle(this.selectedYear, this.selectedMake, this.selectedModel, style);
|
||||||
this.setVehicle();
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
setVehicle() {
|
setVehicle(year, make, model, style) {
|
||||||
return this.dispatchStoreAction(this.storeActions.SET_VEHICLE, {
|
return this.dispatchStoreAction(this.storeActions.SET_VEHICLE, {
|
||||||
year: this.$store.getters.vehicle.year,
|
year: year,
|
||||||
make: this.$store.getters.vehicle.make,
|
make: make,
|
||||||
model: this.$store.getters.vehicle.model,
|
model: model,
|
||||||
style: this.$store.getters.vehicle.style,
|
style: style,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -207,42 +290,29 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
navigateForward() {
|
navigateForward() {
|
||||||
|
this.dispatchStoreAction(
|
||||||
|
storeActions.SAVE_VEHICLE,
|
||||||
|
{
|
||||||
|
year: this.selectedYear,
|
||||||
|
make: this.selectedMake,
|
||||||
|
model: this.selectedModel,
|
||||||
|
style: this.selectedStyle,
|
||||||
|
},
|
||||||
|
false
|
||||||
|
);
|
||||||
this.$router.navigateWithSaving(this.navigationScenarios.CLICKED_FORWARD, this.$route);
|
this.$router.navigateWithSaving(this.navigationScenarios.CLICKED_FORWARD, this.$route);
|
||||||
},
|
},
|
||||||
|
|
||||||
async updateYearValues() {
|
initializeYearComponent(initialData) {
|
||||||
return await baseMixin.methods.dispatchStoreAction(storeActions.GET_VEHICLE_YEARS, {});
|
this.yearOptions = initialData;
|
||||||
},
|
},
|
||||||
|
initializeMMSComponent(makeOptions, modelOptions, styleOptions) {
|
||||||
async updateMakeValues() {
|
this.makeOptions = makeOptions;
|
||||||
return await baseMixin.methods.dispatchStoreAction(storeActions.GET_VEHICLE_MAKES, {
|
this.modelOptions = modelOptions;
|
||||||
year: store.getters.vehicle.year,
|
this.styleOptions = styleOptions;
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
async updateModelValues() {
|
|
||||||
return await baseMixin.methods.dispatchStoreAction(storeActions.GET_VEHICLE_MODELS, {
|
|
||||||
year: store.getters.vehicle.year,
|
|
||||||
|
|
||||||
make: store.getters.vehicle.make,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
async updateStyleValues() {
|
|
||||||
return baseMixin.methods.dispatchStoreAction(storeActions.GET_VEHICLE_STYLES, {
|
|
||||||
year: store.getters.vehicle.year,
|
|
||||||
make: store.getters.vehicle.make,
|
|
||||||
model: store.getters.vehicle.model,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
computed: {
|
|
||||||
displayGeneric() {
|
|
||||||
return !this.selectedStyle;
|
|
||||||
},
|
},
|
||||||
selectedYearfromStore() {
|
selectedYearfromStore() {
|
||||||
return store.getters.vehicle.year;
|
return store.getters.vehicle.year?.toString();
|
||||||
},
|
},
|
||||||
selectedMakefromStore() {
|
selectedMakefromStore() {
|
||||||
return store.getters.vehicle.make;
|
return store.getters.vehicle.make;
|
||||||
|
|
@ -253,6 +323,32 @@ export default {
|
||||||
selectedStylefromStore() {
|
selectedStylefromStore() {
|
||||||
return store.getters.vehicle.style;
|
return store.getters.vehicle.style;
|
||||||
},
|
},
|
||||||
|
async getMakeOptions(year) {
|
||||||
|
return await baseMixin.methods.dispatchStoreAction(storeActions.GET_VEHICLE_MAKES, {
|
||||||
|
year: year,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
async getModelOptions(year, make) {
|
||||||
|
return await baseMixin.methods.dispatchStoreAction(storeActions.GET_VEHICLE_MODELS, {
|
||||||
|
year: year,
|
||||||
|
make: make,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
async getStyleOptions(year, make, model) {
|
||||||
|
return await baseMixin.methods.dispatchStoreAction(storeActions.GET_VEHICLE_STYLES, {
|
||||||
|
year: year,
|
||||||
|
make: make,
|
||||||
|
model: model,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
displayGeneric() {
|
||||||
|
return !this.selectedStyle;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,9 @@
|
||||||
v-model="vin"
|
v-model="vin"
|
||||||
customInputId="vin"
|
customInputId="vin"
|
||||||
isRequired
|
isRequired
|
||||||
validationRules="vin-required|vin-format"
|
:validationRules="
|
||||||
|
!vinPopulatedOnPageLoad ? 'vin-required|vin-format' : ''
|
||||||
|
"
|
||||||
:isDisabled="vinPopulatedOnPageLoad"
|
:isDisabled="vinPopulatedOnPageLoad"
|
||||||
maxLength="17"
|
maxLength="17"
|
||||||
:mask="vinMask"
|
:mask="vinMask"
|
||||||
|
|
@ -348,37 +350,22 @@ export default {
|
||||||
// If a VIN has already been found. Validate the Service Zip (in case of changes)
|
// If a VIN has already been found. Validate the Service Zip (in case of changes)
|
||||||
const zipCodeData = await this.getZipCodeData(this.serviceZipCode);
|
const zipCodeData = await this.getZipCodeData(this.serviceZipCode);
|
||||||
|
|
||||||
// Check if Service Zip entered is serviceable then save the ZIP info and email address
|
// Check if Service Zip entered is serviceable then save the ZIP info
|
||||||
if (zipCodeData.isServiceable) {
|
if (zipCodeData.isServiceable) {
|
||||||
//Only save the service location if the zip changed or we lack zipCodeCtu
|
//Only save the zipCode, state, and zipCodeCtu if the zip changed or we lack zipCodeCtu
|
||||||
if (
|
if (
|
||||||
this.$store.getters.order.serviceLocation.zipCode != this.serviceZipCode ||
|
this.$store.getters.order.serviceLocation.zipCode != this.serviceZipCode ||
|
||||||
!this.$store.getters.order.serviceLocation.zipCodeCtu
|
!this.$store.getters.order.serviceLocation.zipCodeCtu
|
||||||
) {
|
) {
|
||||||
const vehicleRegistrationInfo = this.$store.getters.vehicle.registration;
|
await this.dispatchStoreAction(
|
||||||
if (vehicleRegistrationInfo.zipCode == this.serviceZipCode) {
|
storeActions.SAVE_SERVICE_ZIP_CODE_INFO,
|
||||||
await this.dispatchStoreAction(
|
{
|
||||||
storeActions.SAVE_SERVICE_LOCATION,
|
state: zipCodeData.state,
|
||||||
{
|
zipCode: this.serviceZipCode,
|
||||||
address: vehicleRegistrationInfo.address,
|
zipCodeCtu: zipCodeData.zipCodeCtu,
|
||||||
city: vehicleRegistrationInfo.city,
|
},
|
||||||
state: vehicleRegistrationInfo.state,
|
false
|
||||||
zipCode: vehicleRegistrationInfo.zipCode,
|
);
|
||||||
zipCodeCtu: zipCodeData.zipCodeCtu,
|
|
||||||
},
|
|
||||||
false
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
await this.dispatchStoreAction(
|
|
||||||
storeActions.SAVE_SERVICE_ZIP_CODE_INFO,
|
|
||||||
{
|
|
||||||
state: zipCodeData.state,
|
|
||||||
zipCode: this.serviceZipCode,
|
|
||||||
zipCodeCtu: zipCodeData.zipCodeCtu,
|
|
||||||
},
|
|
||||||
false
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.dispatchStoreAction(storeActions.SAVE_EMAIL, this.emailAddress, false);
|
await this.dispatchStoreAction(storeActions.SAVE_EMAIL, this.emailAddress, false);
|
||||||
|
|
|
||||||
|
|
@ -446,7 +446,9 @@ export default {
|
||||||
|
|
||||||
const payment = store.getters.payment;
|
const payment = store.getters.payment;
|
||||||
|
|
||||||
if (payment.isInsurance && payment.insuranceCoverage.isVerified) {
|
if (store.getters.order.referralNumber?.length === 6) {
|
||||||
|
navigateToHeritageFunnel({ loadingModal: self.$refs.loadingModal });
|
||||||
|
} else if (payment.isInsurance && payment.insuranceCoverage.isVerified) {
|
||||||
navigateToHeritageFunnel({ loadingModal: self.$refs.loadingModal });
|
navigateToHeritageFunnel({ loadingModal: self.$refs.loadingModal });
|
||||||
} else {
|
} else {
|
||||||
self.$router.navigateWithSaving(
|
self.$router.navigateWithSaving(
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,7 @@ const navigationScenarios = {
|
||||||
CLICKED_VEHICLE_EDIT: "CLICKED_VEHICLE_EDIT",
|
CLICKED_VEHICLE_EDIT: "CLICKED_VEHICLE_EDIT",
|
||||||
CLICKED_DAMAGE_EDIT: "CLICKED_DAMAGE_EDIT",
|
CLICKED_DAMAGE_EDIT: "CLICKED_DAMAGE_EDIT",
|
||||||
CLICKED_SERVICE_PACKAGE_EDIT: "CLICKED_SERVICE_PACKAGE_EDIT",
|
CLICKED_SERVICE_PACKAGE_EDIT: "CLICKED_SERVICE_PACKAGE_EDIT",
|
||||||
|
CLICKED_SERVICE_LOCATION_EDIT: "CLICKED_SERVICE_LOCATION_EDIT",
|
||||||
};
|
};
|
||||||
|
|
||||||
export { navigationScenarios };
|
export { navigationScenarios };
|
||||||
|
|
|
||||||
|
|
@ -480,6 +480,10 @@ const routingTable = function (store) {
|
||||||
scenario: navigationScenarios.CLICKED_BACK,
|
scenario: navigationScenarios.CLICKED_BACK,
|
||||||
destinationFmgPageValue: fmgPageValues.CUSTOMER_DETAILS,
|
destinationFmgPageValue: fmgPageValues.CUSTOMER_DETAILS,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
scenario: navigationScenarios.CLICKED_SERVICE_LOCATION_EDIT,
|
||||||
|
destinationFmgPageValue: fmgPageValues.SERVICE_LOCATION,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -535,6 +535,9 @@ export const getters = {
|
||||||
},
|
},
|
||||||
eventBus: (state) => state.applicationUser.eventBus,
|
eventBus: (state) => state.applicationUser.eventBus,
|
||||||
damage: (state) => state.order.damage,
|
damage: (state) => state.order.damage,
|
||||||
|
hasExactlyOneChip: (state) => {
|
||||||
|
return state.order.damage?.numberOfChips === 1;
|
||||||
|
},
|
||||||
hasAnyNonWindshieldGlassParts: (state) => {
|
hasAnyNonWindshieldGlassParts: (state) => {
|
||||||
const nonWindshieldItems = state.order.damage.glassToReplace?.filter(
|
const nonWindshieldItems = state.order.damage.glassToReplace?.filter(
|
||||||
(glassToReplace) => glassToReplace.glassLocation != "Windshield"
|
(glassToReplace) => glassToReplace.glassLocation != "Windshield"
|
||||||
|
|
@ -766,11 +769,12 @@ export const actions = {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
getDamageOptions(context, { carId }) {
|
getDamageOptions(context, { carId, zipCode }) {
|
||||||
return globalMethods.callHttpClient({
|
return globalMethods.callHttpClient({
|
||||||
methods: endpoints.GetDamageOptions.method,
|
methods: endpoints.GetDamageOptions.method,
|
||||||
endpoint: `${endpoints.GetDamageOptions.url}/${carId}`,
|
endpoint: `${endpoints.GetDamageOptions.url}/${carId}`,
|
||||||
payload: {},
|
payload: {},
|
||||||
|
additionalSuccessEventDataHandler: (response) => "QueryStringZip: " + zipCode,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -1622,6 +1626,25 @@ export const actions = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
saveVehicle(context, { year, make, model, style }) {
|
||||||
|
context.dispatch(storeActions.RESET_DAMAGE_STATE_AND_DEPENDENCIES);
|
||||||
|
context.dispatch(storeActions.RESET_REGISTRATION_STATE_AND_DEPENDENCIES);
|
||||||
|
context.dispatch(storeActions.RESET_PARTS_STATE_AND_DEPENDENCIES);
|
||||||
|
|
||||||
|
if (context.state.order.vehicle.year !== year) {
|
||||||
|
context.commit(storeMutations.UPDATE_YEAR, year);
|
||||||
|
}
|
||||||
|
if (context.state.order.vehicle.make !== make) {
|
||||||
|
context.commit(storeMutations.UPDATE_MAKE, make);
|
||||||
|
}
|
||||||
|
if (context.state.order.vehicle.model !== model) {
|
||||||
|
context.commit(storeMutations.UPDATE_MODEL, model);
|
||||||
|
}
|
||||||
|
if (context.state.order.vehicle.style !== style) {
|
||||||
|
context.commit(storeMutations.UPDATE_STYLE, style);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
saveVehicleDamage(
|
saveVehicleDamage(
|
||||||
context,
|
context,
|
||||||
{ isWindshieldRepair, selectedGlassToReplace, selectedWindshieldChipCount }
|
{ isWindshieldRepair, selectedGlassToReplace, selectedWindshieldChipCount }
|
||||||
|
|
|
||||||
|
|
@ -1702,6 +1702,59 @@ describe("Actions", () => {
|
||||||
expect(commit).toBeCalledWith(storeMutations.UPDATE_VEHICLE_IMAGE_COLOR, null);
|
expect(commit).toBeCalledWith(storeMutations.UPDATE_VEHICLE_IMAGE_COLOR, null);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("saveVehicle, should save vehicle info", () => {
|
||||||
|
// Arrange
|
||||||
|
const context = state;
|
||||||
|
|
||||||
|
context.state = {
|
||||||
|
order: {
|
||||||
|
vehicle: {
|
||||||
|
year: "2016",
|
||||||
|
make: "Toyota",
|
||||||
|
model: "Accord",
|
||||||
|
style: "SUV",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const commit = jest.fn();
|
||||||
|
const dispatch = jest.fn();
|
||||||
|
|
||||||
|
context.commit = commit;
|
||||||
|
context.dispatch = dispatch;
|
||||||
|
|
||||||
|
//Act
|
||||||
|
const payload = {
|
||||||
|
year: "2015",
|
||||||
|
make: "Honda",
|
||||||
|
model: "Civic",
|
||||||
|
style: "Sedan",
|
||||||
|
};
|
||||||
|
actions.saveVehicle(context, payload);
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
expect(dispatch).toHaveBeenNthCalledWith(
|
||||||
|
1,
|
||||||
|
storeActions.RESET_DAMAGE_STATE_AND_DEPENDENCIES
|
||||||
|
);
|
||||||
|
expect(dispatch).toHaveBeenNthCalledWith(
|
||||||
|
2,
|
||||||
|
storeActions.RESET_REGISTRATION_STATE_AND_DEPENDENCIES
|
||||||
|
);
|
||||||
|
if (context.state.order.vehicle.year !== payload.year) {
|
||||||
|
expect(commit).toBeCalledWith(storeMutations.UPDATE_YEAR, payload.year);
|
||||||
|
}
|
||||||
|
if (context.state.order.vehicle.make !== payload.make) {
|
||||||
|
expect(commit).toBeCalledWith(storeMutations.UPDATE_MAKE, payload.make);
|
||||||
|
}
|
||||||
|
if (context.state.order.vehicle.model !== payload.model) {
|
||||||
|
expect(commit).toBeCalledWith(storeMutations.UPDATE_MODEL, payload.model);
|
||||||
|
}
|
||||||
|
if (context.state.order.vehicle.style !== payload.style) {
|
||||||
|
expect(commit).toBeCalledWith(storeMutations.UPDATE_STYLE, payload.style);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
it("saveVehicleDamage, should wipe out damage if different", () => {
|
it("saveVehicleDamage, should wipe out damage if different", () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const context = state;
|
const context = state;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue