Merge pull request #815 from Safelite/bug/brydon/SSR-1440

Bug/brydon/ssr 1440
This commit is contained in:
michaela-brydon-safelite 2024-08-19 12:58:19 -04:00 committed by GitHub
commit f65d43d2e9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 1025 additions and 751 deletions

View file

@ -24,7 +24,7 @@ export default {
}
const imageUrl = (this.mainStore.hasSubmittedOrder())
? this.mainStore.submittedOrder.vehicle.imageUrl
? this.mainStore.getSubmittedOrder().vehicle.imageUrl
: this.mainStore.order.vehicle.imageUrl;
if (!imageUrl || imageUrl === 'NULL') {
@ -54,7 +54,7 @@ export default {
},
methods: {
getUnmatchedVehicleIcon() {
const category = this.mainStore.submittedOrder?.vehicle.category ?? this.mainStore.order.vehicle.category;
const category = this.mainStore.getSubmittedOrder()?.vehicle.category ?? this.mainStore.order.vehicle.category;
switch (category) {
case this.vehicleCategories.CAR:
return this.carUnmatchedVehicleIcon;

View file

@ -2,10 +2,11 @@
import calendarOptions from '@/constants/calendar-options';
// Supporting Files
import { shallowMount } from '@vue/test-utils';
import { shallowMount, mount } from '@vue/test-utils';
import { getMountOptions } from '@/helpers/unit-test-helper.js';
import { useMainStore } from '@/store';
import addToCalendar from '@/layouts/order-confirmation/add-to-calendar/add-to-calendar.vue';
import { createTestingPinia } from '@pinia/testing';
const appointmentText = 'Appointment content';
function setupMocks({ customMountOptions }) {
@ -24,6 +25,59 @@ function setupMocks({ customMountOptions }) {
return { wrapper };
}
const calendarModalQuestionStub = {
render: () => {}
};
const mockMixin = {
methods: {
getCmsContent: jest.fn().mockImplementation(() => appointmentText)
}
};
function getMountedComponent(mainInitialState = {}, initialData = {}, methodToRun = () => {}, mixin = mockMixin) {
const mountOptions = getMountOptions({
router: {
navigate: jest.fn(),
navigateToExternalUrl: jest.fn()
}
});
mountOptions.global.stubs = {
// siteFooter: footerStub,
// siteHeader: headerStub,
// vehicleBanner: vehicleBannerStub,
// addToCalendar: addToCalendarStub
calendarModalQuestion: calendarModalQuestionStub
};
const testingPinia = createTestingPinia({
initialState: {
main: mainInitialState
}
});
useMainStore(testingPinia);
methodToRun();
mountOptions.global.mixins[0].methods.getSettingValue = jest.fn(() => 'false');
mountOptions.global.plugins = [testingPinia];
mountOptions.mixins = [mixin];
mountOptions.data = () => (
initialData
);
// const apiResponses = {
// supportingItems: []
// };
//const apiPromise = Promise.resolve(apiResponses);
// settleAllPromises.mockImplementation(() => apiPromise);
//fetchCmsContentForPage.mockImplementation(() => Promise.resolve());
const wrapper = shallowMount(addToCalendar, mountOptions);
wrapper.vm.$refs.calendarModalQuestion.openModal = jest.fn();
return { wrapper };
}
beforeEach(() => {
jest.restoreAllMocks();
jest.clearAllMocks();
@ -76,10 +130,52 @@ afterEach(() => {
jest.clearAllMocks();
});
const sessionStorage = {
schedule: {
date: '2019-01-01',
startTime: '09:00',
endTime: '10:00',
routeCode: '000'
},
lineItems: {
glassParts: [
{
partNumber: 'ABC123'
}
],
supportingItems: []
},
serviceLocation: {
address: '',
address2: null,
city: '',
state: 'AZ',
appointmentType: 'Inshop',
zipCode: '12345',
zipCodeCtu: '01234',
provider: {
providerNumber: '123',
address: {
streetAddress: 'test1',
city: 'test',
state: 'AZ',
zipCode: '12345',
zipCodeCtu: '01234'
}
}
},
damage: {
isRepair: false
},
referralNumber: '1234567',
payment: {
isInsurance: true
}
};
describe('Add-to-calendar methods...', () => {
test('Add-to-calendar should trigger openModal method', () => {
// Arrange
const { wrapper } = setupMocks({
customMountOptions: {
propsData: {

View file

@ -30,8 +30,6 @@ import { getDateFormat,
addMinutes } from '@/helpers/date-helper';
import { AppointmentTypeStrings, RouteCodeFlags } from '@/constants/schedule-constants';
import { getCalendarFile, download } from '@/helpers/add-to-calendar-helper';
import { useMainStore } from '@/store';
import serviceType from '@/constants/service-type';
import applicationConfig from '@/constants/application-config.js';
import calendarModalQuestion from '@/layouts/order-confirmation/add-to-calendar/calendar-modal-question/calendar-modal-question.vue';
@ -53,12 +51,11 @@ export default {
appointmentType: String,
scheduleDate: String,
scheduleStartTime: String,
scheduleEndTime: String
},
setup() {
const mainStore = useMainStore();
const { submittedOrder } = mainStore;
return { mainStore, submittedOrder };
scheduleEndTime: String,
hasRecalibrationPart: Boolean,
uniqueId: String,
isRepair: Boolean,
routeCode: String
},
data() {
return {
@ -116,23 +113,15 @@ export default {
AddToCalendar_SameDayDropOff_Body() {
return this.getCmsContent(this.sameDayDropOffWidgetName, 'BodyText');
},
UniqueId() {
return this.submittedOrder.referralNumber?.toString();
},
ServiceType() {
const { isRepair } = this.submittedOrder.damage;
const { hasRecalibrationPart } = this.mainStore;
if (!isRepair) {
if (hasRecalibrationPart) {
if (!this.isRepair) {
if (this.hasRecalibrationPart) {
return serviceType.REPLACEMENT_AND_RECALIBRATION;
}
return serviceType.REPLACEMENT;
}
return serviceType.REPAIR;
},
RouteCode() {
return this.submittedOrder.schedule.routeCode;
},
Appointment() {
let subject = '';
let location = '';
@ -153,10 +142,10 @@ export default {
} else {
location = this.providerFullAddress?.replace('<br/>', '');
if (this.appointmentType === AppointmentTypeStrings.DROP_OFF) {
if (this.RouteCode.includes(RouteCodeFlags.OVERNIGHT_DROP_OFF)) {
if (this.routeCode.includes(RouteCodeFlags.OVERNIGHT_DROP_OFF)) {
subject = this.AddToCalendar_OvernightDropOff_Subject;
body = this.AddToCalendar_OvernightDropOff_Body;
} else if (this.RouteCode.includes(RouteCodeFlags.ALL_DAY_DROP_OFF)) {
} else if (this.routeCode.includes(RouteCodeFlags.ALL_DAY_DROP_OFF)) {
if (this.IsSameDayDropOff) {
subject = this.AddToCalendar_SameDayDropOff_Subject;
endDateTime = addMinutes(startDateTime, 120);
@ -196,7 +185,7 @@ export default {
Location: location,
StartDate: startDateTime,
EndDate: endDateTime,
RefrrlSeqNum: this.UniqueId,
RefrrlSeqNum: this.uniqueId,
Body: body,
IsHTML: isHTML,
Duration: duration
@ -287,10 +276,6 @@ export default {
const calBody = getCalendarFile(calFile);
download('SafeliteAppointment.ics', calBody);
}
// getInShopAppointmentText() {
// const test = this.getCmsContent('AddToCalendar_InShop_TEST', 'Text');
// return test;
// }
}
};
</script>

File diff suppressed because it is too large Load diff

View file

@ -7,7 +7,7 @@
<div class="container-fluid fade-on-route-transition">
<div class="row justify-content-center">
<div class="col-md-6 px-0 px-md-2">
<siteHeader cmsWidgetName="SiteHeaderWidget" />
<siteHeader :cmsWidgetName="widgets.siteHeader" />
</div>
</div>
<div class="row justify-content-center">
@ -21,13 +21,13 @@
<div class="appointment-details">
<div>
<vehicleBanner
cmsWidgetName="VehicleBannerWidget"
:cmsWidgetName="widgets.vehicleBanner"
:displayGenericVehicleImage="false">
</vehicleBanner>
</div>
<div class="appointment-date-time text-center mt-4">
<p>{{ appointmentDateFormatted }}</p>
<p class="mt-2">{{ appointmentTimeFormatted }}</p>
<p>{{ formatDate(schedule.date) }}</p>
<p class="mt-2">{{ appointmentTimeText }}</p>
</div>
<addToCalendar
mobileWidgetName="AddToCalendar_Mobile"
@ -36,14 +36,16 @@
overnightDropOffWidgetName="AddToCalendar_OvernightDropOff"
allDayDropOffWidgetName="AddToCalendar_AllDayDropOff"
sameDayDropOffWidgetName="AddToCalendar_SameDayDropOff"
:serviceLocationFullAddress="
serviceLocationFullAddress
"
:serviceLocationFullAddress="serviceLocationFullAddress"
:providerFullAddress="providerFullAddress"
:appointmentType="appointmentType"
:scheduleDate="appointmentDate"
:scheduleStartTime="appointmentStartTime"
:scheduleEndTime="appointmentEndTime" />
:scheduleDate="schedule.date"
:scheduleStartTime="schedule.startTime"
:scheduleEndTime="schedule.endTime"
:routeCode="schedule.routeCode"
:hasRecalibrationPart="hasRecalibrationPart"
:uniqueId="referralNumber"
:isRepair="isRepair" />
<div
class="appointment-text text-center lh-base"
v-html="appointmentWordingText"></div>
@ -54,7 +56,7 @@
<hr class="mb-0" />
<div>
<cartDropdown
:showAsPaid="isPayInAdvance"
:showAsPaid="payment.isPayInAdvance"
:readOnly="true"
:isInitiallyExpanded="false"
:showDropdownHeader="true"
@ -69,7 +71,7 @@
<siteFooter
v-if="carrierUrl"
ref="siteFooter"
cmsWidgetName="SiteFooterWidget"
:cmsWidgetName="widgets.siteFooter"
:isStackedVertically="true"
:isForwardActionDisabled="!meta.valid"
@ForwardClicked="forwardButtonAction"
@ -90,7 +92,8 @@ import cartDropdown from '@/iss-components/cart-dropdown/cart-dropdown.vue';
// Supporting files
import {
fetchCmsContentForPage,
processIfStatements
processIfStatements,
getStringWithCustomValues
} from '@/helpers/cms-content-helper';
import settleAllPromises from '@/helpers/layout-helper';
import { Form } from 'vee-validate';
@ -105,7 +108,7 @@ import {
import { toTitleCase } from '@/helpers/text-helper.js';
import { AppointmentTypeStrings } from '@/constants/schedule-constants';
import applicationConfig from '@/constants/application-config';
import submitType from '@/constants/submit-type';
import widgetFields from '@/constants/cms-widget-fields.js';
export default {
name: 'order-confirmation',
@ -139,193 +142,169 @@ export default {
},
setup() {
const mainStore = useMainStore();
const { submittedOrder } = mainStore;
const submittedOrder = mainStore.getSubmittedOrder();
return { mainStore, submittedOrder };
},
data() {
var {
vehicle,
serviceLocation,
schedule,
customer,
payment,
customerPortalLoginToken,
damage,
referralNumber } = this.submittedOrder;
var { issConfig, hasRecalibrationPart } = this.mainStore;
return {
vehicle,
customerEmail: customer?.emailAddress,
payment,
schedule,
serviceLocation,
appointmentType: serviceLocation.appointmentType,
providerAddress: serviceLocation?.provider?.address,
customerPortalLoginToken,
carrierName: issConfig.clientName,
carrierUrl: issConfig.successReturnURL,
isRepair: damage.isRepair,
hasRecalibrationPart,
referralNumber: referralNumber?.toString(),
widgets: {
siteHeader: 'SiteHeaderWidget',
vehicleBanner: 'VehicleBannerWidget',
emailConfirmation: 'EmailConfirmationWordingWidget',
orderConfirmation: 'OrderConfirmationContent',
mobile: 'MobileWordingWidget',
dropOffAndInShop: 'DropOffAndInShopWordingWidget',
siteFooter: 'SiteFooterWidget'
},
}
},
computed: {
carrierName() {
return this.mainStore.issConfig.clientName;
},
carrierUrl() {
return this.mainStore.issConfig.successReturnURL;
customValueMap() {
return {
inShopAppointment: this.isInShopAppointment,
dropOffAppointment: this.isDropOffAppointment,
vehicleYear: this.vehicle?.year,
vehicleMake: this.vehicle?.make,
vehicleModel: this.vehicle?.model,
address: this.appointmentLocation,
inShopDuration: this.inShopAppointmentDuration,
email: this.customerEmail,
CUSTOMER_PORTAL_URL: applicationConfig.CUSTOMER_PORTAL_URL,
CUSTOMER_PORTAL_LOGIN_TOKEN: this.customerPortalLoginToken
}
},
confirmationEmailText() {
return this.getCmsContent(
'EmailConfirmationWordingWidget',
'BodyText'
)
?.replaceAll(
'{custom:CUSTOMER_PORTAL_URL}',
applicationConfig.CUSTOMER_PORTAL_URL
)
?.replaceAll(
'{custom:CUSTOMER_PORTAL_LOGIN_TOKEN}',
this.submittedOrder.customerPortalLoginToken
)
var content = this.getCmsContentWithCustomValues(
this.widgets.emailConfirmation,
widgetFields.CONTENT_GROUP_WIDGET.BODY_TEXT);
return content
?.replaceAll('&lt;', '<')
?.replaceAll('&gt;', '>');
},
orderConfirmationHeaderText() {
return this.getCmsContent('OrderConfirmationContent', 'HeaderText');
return this.getCmsContent(
this.widgets.orderConfirmation,
widgetFields.CONTENT_GROUP_WIDGET.HEADER_TEXT);
},
orderConfirmationImage() {
return this.getCmsContent('OrderConfirmationContent', 'Image');
},
appointmentType() {
return this.submittedOrder.serviceLocation.appointmentType;
},
appointmentDate() {
return this.submittedOrder.schedule.date;
},
appointmentStartTime() {
return this.submittedOrder.schedule.startTime;
},
appointmentEndTime() {
return this.submittedOrder.schedule.endTime;
},
appointmentDateFormatted() {
// This conversion ensures we don't get get GMT induced date changes
const dateObject = convertDateStringToDate(this.appointmentDate);
// Ex: Tuesday, April 22
return dateObject.toLocaleDateString('en-us', {
weekday: 'long',
month: 'long',
day: 'numeric'
});
},
appointmentTimeFormatted() {
const formattedTime = this.formatAppointmentTime(this.appointmentType);
return formattedTime;
return this.getCmsContent(
this.widgets.orderConfirmation,
widgetFields.CONTENT_GROUP_WIDGET.IMAGE);
},
mobileWordingText() {
return this.getCmsContent('MobileWordingWidget', 'BodyText');
return this.getCmsContentWithCustomValues(
this.widgets.mobile,
widgetFields.CONTENT_GROUP_WIDGET.BODY_TEXT);
},
mobileWordingText2() {
return this.getCmsContent('MobileWordingWidget', 'BodyText2');
},
dropOffAndInShopWordingText() {
return this.getCmsContent(
'DropOffAndInShopWordingWidget',
'BodyText'
);
this.widgets.mobile,
widgetFields.CONTENT_GROUP_WIDGET.BODY_TEXT_2);
},
dropOffAndInShopWordingText2() {
return this.getBodyText2FromCms('DropOffAndInShopWordingWidget');
nonMobileWordingText() {
return this.getCmsContentWithCustomValues(
this.widgets.dropOffAndInShop,
widgetFields.CONTENT_GROUP_WIDGET.BODY_TEXT);
},
serviceLocationAddress() {
return this.submittedOrder.serviceLocation.address;
nonMobileWordingText2() {
return this.getCmsContentWithCustomValues(
this.widgets.dropOffAndInShop,
widgetFields.CONTENT_GROUP_WIDGET.BODY_TEXT_2);
},
serviceLocationAddress2() {
return this.submittedOrder.serviceLocation.address2;
appointmentTimeText() {
const { startTime, endTime } = this.schedule;
if (this.isDropOffAppointment){
return 'Drop off before 9:30 AM';
}
if (this.isInShopAppointment){
const formattedStartTime = get12HourTimeFormat(startTime);
return `at ${formattedStartTime}`
}
if (this.isMobileAppointment) {
const mobileStartTime = get12HourTimeMobileFormat(startTime);
const mobileEndTime = get12HourTimeMobileFormat(endTime);
return `Between ${mobileStartTime} - ${mobileEndTime}`;
}
return null;
},
serviceLocationCity() {
return this.submittedOrder.serviceLocation.city;
},
serviceLocationState() {
return this.submittedOrder.serviceLocation.state;
},
serviceLocationZipCode() {
return this.submittedOrder.serviceLocation.zipCode;
appointmentLocation() {
if (this.isMobileAppointment){
return this.serviceLocationFullAddress;
}
if (this.isDropOffAppointment || this.isInShopAppointment){
return this.providerFullAddress;
}
return null
},
serviceLocationFullAddress() {
// eslint-disable-next-line max-len
return `${this.serviceLocationAddress}, ${
this.serviceLocationAddress2
? `${this.serviceLocationAddress2},`
: ''
}<br/> ${this.serviceLocationCity}, ${this.serviceLocationState} ${
this.serviceLocationZipCode
}`;
},
providerAddress() {
return toTitleCase(this.submittedOrder.serviceLocation.provider.address
.streetAddress);
},
providerCity() {
return toTitleCase(this.submittedOrder.serviceLocation.provider.address.city);
},
providerState() {
return this.submittedOrder.serviceLocation.provider.address.state;
},
providerZipCode() {
return this.submittedOrder.serviceLocation.provider.address.zipCode;
var { address, address2, city, state, zipCode } = this.serviceLocation;
return `${address ?? ''}, ${address2 ? `${address2},` : ''}<br/> ${city ?? ''}, ${state ?? ''} ${zipCode ?? ''}`;
},
providerFullAddress() {
// eslint-disable-next-line max-len
return this.submittedOrder.serviceLocation?.provider?.address
? `${this.providerAddress},<br/> ${this.providerCity}, ${this.providerState} ${this.providerZipCode}`
var { streetAddress, city, state, zipCode } = this.providerAddress;
return streetAddress
? `${toTitleCase(streetAddress)},<br/> ${toTitleCase(city)}, ${state ?? ''} ${zipCode ?? ''}`
: '';
},
appointmentWordingText() {
switch (this.appointmentType) {
case AppointmentTypeStrings.MOBILE:
case AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP:
return this.mobileWordingText?.replaceAll(
'{custom:address}',
this.serviceLocationFullAddress
);
case AppointmentTypeStrings.DROP_OFF:
return this.dropOffAndInShopWordingText?.replaceAll(
'{custom:address}',
this.providerFullAddress
);
case AppointmentTypeStrings.IN_SHOP:
return this.dropOffAndInShopWordingText?.replaceAll(
'{custom:address}',
this.providerFullAddress
);
default:
return null;
if (this.isMobileAppointment){
return this.mobileWordingText;
}
if (this.isInShopAppointment || this.isDropOffAppointment){
return this.nonMobileWordingText;
}
return null;
},
appointmentWordingText2() {
switch (this.appointmentType) {
case AppointmentTypeStrings.MOBILE:
case AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP:
return this.mobileWordingText2;
case AppointmentTypeStrings.DROP_OFF:
return this.dropOffAndInShopWordingText2;
case AppointmentTypeStrings.IN_SHOP:
return this.dropOffAndInShopWordingText2?.replaceAll(
'{custom:inShopDuration}',
this.inShopAppointmentDuration
);
default:
return null;
if (this.isMobileAppointment){
return this.mobileWordingText2;
}
if (this.isInShopAppointment || this.isDropOffAppointment){
return this.nonMobileWordingText2;
}
return null;
},
mobileAppointment() {
return (
this.submittedOrder.serviceLocation.appointmentType
=== AppointmentTypeStrings.MOBILE
|| this.submittedOrder.serviceLocation.appointmentType
=== AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP
);
isMobileAppointment() {
const mobileAppointmentTypes = [
AppointmentTypeStrings.MOBILE,
AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP
]
return mobileAppointmentTypes.includes(this.appointmentType);
},
inShopAppointment() {
return (
this.submittedOrder.serviceLocation.appointmentType
=== AppointmentTypeStrings.IN_SHOP
);
isInShopAppointment() {
return this.appointmentType === AppointmentTypeStrings.IN_SHOP;
},
dropOffAppointment() {
return (
this.submittedOrder.serviceLocation.appointmentType
=== AppointmentTypeStrings.DROP_OFF
);
isDropOffAppointment() {
return this.appointmentType === AppointmentTypeStrings.DROP_OFF;
},
inShopAppointmentDuration() {
const inshopDurationTime = getDisplayTextForDurationLength(
this.submittedOrder.schedule.jobMinMinutes,
this.submittedOrder.schedule.jobMaxMinutes
return getDisplayTextForDurationLength(
this.schedule.jobMinMinutes,
this.schedule.jobMaxMinutes
);
return inshopDurationTime;
},
isPayInAdvance() {
return this.submittedOrder.payment.isPayInAdvance;
},
selectedVaps() {
return this.submittedOrder.lineItems.vaps;
}
},
mounted() {
@ -404,38 +383,24 @@ export default {
forwardButtonAction() {
this.$router.navigateToExternalUrl(this.carrierUrl);
},
formatAppointmentTime(appointmentType) {
switch (appointmentType) {
case AppointmentTypeStrings.MOBILE:
case AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP:
// eslint-disable-next-line max-len
return `Between ${get12HourTimeMobileFormat(this.appointmentStartTime)} - ${get12HourTimeMobileFormat(this.appointmentEndTime)}`;
case AppointmentTypeStrings.DROP_OFF:
return 'Drop off before 9:30 AM';
case AppointmentTypeStrings.IN_SHOP:
return `at ${get12HourTimeFormat(this.appointmentStartTime)}`;
default:
return null;
}
},
processIfStatements,
getBodyText2FromCms(cmsWidgetName) {
const body2Text = this.getCmsContent(cmsWidgetName, 'BodyText2');
return this.processIfStatements(
body2Text,
getCmsContentWithCustomValues(widgetName, widgetField) {
const rawText = this.getCmsContent(widgetName, widgetField);
const processedIfStatements = processIfStatements(
rawText,
'custom',
this.getCustomValueFromString
(v) => { return this.customValueMap[v] }
);
return getStringWithCustomValues(processedIfStatements, this.customValueMap);
},
getCustomValueFromString(str) {
switch (str) {
case 'inShopAppointment':
return this.inShopAppointment;
case 'dropOffAppointment':
return this.dropOffAppointment;
default:
return null;
}
formatDate(date) {
// This conversion ensures we don't get get GMT induced date changes
const dateObject = convertDateStringToDate(date);
// Ex: Tuesday, April 22
return dateObject.toLocaleDateString('en-us', {
weekday: 'long',
month: 'long',
day: 'numeric'
});
}
}
};

View file

@ -22,7 +22,11 @@ jest.mock('@/helpers/order-helper.js', () => ({
function setupMocks({ customMountOptions = {}, queryString }, mainInitialState = {}, customMixin = null) {
const mountOptions = getMountOptions({
...customMountOptions,
route: { query: { issPage: issPageValues.PAYMENT_METHOD, ...queryString }, params: {} }
route: { query: { issPage: issPageValues.PAYMENT_METHOD, ...queryString }, params: {} },
router: {
navigate: jest.fn(),
navigateToExternalUrl: jest.fn()
}
});
const testingPinia = createTestingPinia({

View file

@ -301,20 +301,18 @@ export default {
if (this.paymentMethod === paymentMethods.PAY_AT_TIME_OF_SERVICE) {
try {
await submitWorkOrder({ submitType: submitType.SAFELITE }).then(() => {
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD,
this.$route
);
}).catch((submitError) => {
useMainStore().setBailout(bailoutMessage.saveSessionError(submitError.data));
this.$router.navigate(
this.navigationScenarios.SAVE_SESSION_FAILED,
this.$route,
{ issPage: issPageValues.PAYMENT_METHOD }
);
});
await submitWorkOrder({ submitType: submitType.SAFELITE });
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD,
this.$route
);
} catch (error) {
useMainStore().setBailout(bailoutMessage.saveSessionError(error.data));
this.$router.navigate(
this.navigationScenarios.SAVE_SESSION_FAILED,
this.$route,
{ issPage: issPageValues.PAYMENT_METHOD }
);
console.error(`error: response from submit work order:${error.message}`);
}
} else {

View file

@ -8,8 +8,8 @@ import settleAllPromises from '@/helpers/layout-helper.js';
import { fetchCmsContentForPage } from '@/helpers/cms-content-helper';
import { mount } from '@vue/test-utils';
import { createTestingPinia } from '@pinia/testing';
import bailoutMessage from '@/constants/bailoutMessage';
import coverageStatuses from '@/constants/coverage-statuses';
import { deepClone } from '@/helpers/object-helper';
jest.mock('@/helpers/layout-helper.js', () => jest.fn());
@ -54,11 +54,6 @@ function getMountedComponent(mainInitialState = {}, initialData = {}, methodToRu
}
});
const store = useMainStore(testingPinia);
store.submittedOrder = {
...JSON.parse(JSON.stringify(store.order)),
isVerified: store.isVerified,
isUnverified: store.isUnverified
};
store.order = getDefaultState().order;
store.hasSubmittedOrder = jest.fn().mockReturnValue(true);
methodToRun();
@ -80,12 +75,33 @@ function getMountedComponent(mainInitialState = {}, initialData = {}, methodToRu
return { wrapper };
}
const defaultOrder = {
serviceLocation: {
provider: {
companyName: "Hershey",
phoneNumber: "726-117-0377"
}
},
currentDeductible: 479,
isVerified: false,
carrierPhoneNumber: "757-277-0388",
vehicle: {
imageUrl: 'url for image',
category: 'car'
}
}
describe('TPAConfirmation.vue', () => {
describe('Rendering', () => {
let wrapper;
let mockStoreActions;
beforeEach(() => {
mockStoreActions = () => {
useMainStore().getSubmittedOrder = jest.fn().mockImplementation(() => defaultOrder);
};
wrapper = getMountedComponent({}, {}, mockStoreActions).wrapper;
});
test('Should render Site Header', () => {
// Arrange
const { wrapper } = getMountedComponent({});
// Act
const siteHeader = wrapper.findComponent({ ref: 'siteHeader' });
@ -93,9 +109,6 @@ describe('TPAConfirmation.vue', () => {
expect(siteHeader.exists()).toBe(true);
});
test('Should render Vehicle Banner', () => {
// Arrange
const { wrapper } = getMountedComponent({});
// Act
const vehicleBanner = wrapper.findComponent({ ref: 'vehicleBanner' });
@ -103,9 +116,6 @@ describe('TPAConfirmation.vue', () => {
expect(vehicleBanner.exists()).toBe(true);
});
test('Should render Confirmation Body One', () => {
// Arrange
const { wrapper } = getMountedComponent({});
// Act
const bodyOne = wrapper.findComponent({ ref: 'tpaConfirmationBodyOne' });
@ -113,9 +123,6 @@ describe('TPAConfirmation.vue', () => {
expect(bodyOne.exists()).toBe(true);
});
test('Should render Confirmation Body Two', () => {
// Arrange
const { wrapper } = getMountedComponent({});
// Act
const bodyTwo = wrapper.findComponent({ ref: 'tpaConfirmationBodyTwo' });
@ -123,9 +130,6 @@ describe('TPAConfirmation.vue', () => {
expect(bodyTwo.exists()).toBe(true);
});
test('Should render Order Details title', () => {
// Arrange
const { wrapper } = getMountedComponent({});
// Act
const orderDetailsTitle = wrapper.findComponent({ ref: 'tpaConfirmationOrderDetailsTitle' });
@ -133,9 +137,6 @@ describe('TPAConfirmation.vue', () => {
expect(orderDetailsTitle.exists()).toBe(true);
});
test('Should render Order Details body', () => {
// Arrange
const { wrapper } = getMountedComponent({});
// Act
const orderDetailsBody = wrapper.findComponent({ ref: 'tpaConfirmationOrderDetailsBody' });
@ -143,9 +144,6 @@ describe('TPAConfirmation.vue', () => {
expect(orderDetailsBody.exists()).toBe(true);
});
test('Should render Deductible Box', () => {
// Arrange
const { wrapper } = getMountedComponent({});
// Act
const deductibleBox = wrapper.findComponent({ ref: 'deductibleBox' });
@ -160,7 +158,7 @@ describe('TPAConfirmation.vue', () => {
successReturnURL: carrierReturnUrl
}
};
const { wrapper } = getMountedComponent(initialStore);
wrapper = getMountedComponent(initialStore, {}, mockStoreActions).wrapper;
// Act
const siteFooter = wrapper.findComponent({ ref: 'siteFooter' });
@ -169,9 +167,6 @@ describe('TPAConfirmation.vue', () => {
expect(siteFooter.exists()).toBe(true);
});
test('If Essential flow, should not display Site Footer', () => {
// Arrange
const { wrapper } = getMountedComponent();
// Act
const siteFooter = wrapper.findComponent({ ref: 'siteFooter' });
@ -190,7 +185,10 @@ describe('TPAConfirmation.vue', () => {
}
}
};
const { wrapper } = getMountedComponent(initialStore);
const mockStoreActions = () => {
useMainStore().getSubmittedOrder = jest.fn().mockImplementation(() => defaultOrder);
};
const { wrapper } = getMountedComponent(initialStore, {}, mockStoreActions);
const expected = 'Verifying coverage';
// Assert
@ -207,7 +205,12 @@ describe('TPAConfirmation.vue', () => {
currentDeductible
}
};
const { wrapper } = getMountedComponent(initialStore);
const order = deepClone(defaultOrder);
order.isVerified = true;
const mockStoreActions = () => {
useMainStore().getSubmittedOrder = jest.fn().mockImplementation(() => order);
};
const { wrapper } = getMountedComponent(initialStore, {}, mockStoreActions);
const notExpected = 'Verifying coverage';
// Assert
@ -216,26 +219,22 @@ describe('TPAConfirmation.vue', () => {
});
});
describe('Methods', () => {
describe('getCustomValueFromString', () => {
describe.only('getCustomValueFromString', () => {
describe.each([
[false, coverageStatuses.PENDING, 0],
[false, coverageStatuses.PENDING, 500],
[false, coverageStatuses.NO_COVERAGE, 0],
[false, coverageStatuses.NO_COVERAGE, 500],
[false, coverageStatuses.VERIFIED, 0],
[true, coverageStatuses.VERIFIED, 500]
])('with argument deductibleAboveZero', (expected, status, deductible) => {
[false, false, 0],
[false, false, 500],
[false, true, 0],
[true, true, 500]
])('with argument deductibleAboveZero', (expected, isVerified, deductible) => {
test(`returns ${expected} when coverageStatus is ${getEnumName(coverageStatuses, status)} and currentDeductible is ${deductible}`, () => {
// Arrange
const initialStore = {
order: {
insuranceCoverage: {
coverageStatus: status
},
currentDeductible: deductible
}
const order = deepClone(defaultOrder);
order.isVerified = isVerified;
order.currentDeductible = deductible;
const mockStoreActions = () => {
useMainStore().getSubmittedOrder = jest.fn().mockImplementation(() => order);
};
const { wrapper } = getMountedComponent(initialStore);
const { wrapper } = getMountedComponent({}, {}, mockStoreActions);
const argument = 'deductibleAboveZero';
// Act
@ -247,24 +246,20 @@ describe('TPAConfirmation.vue', () => {
});
describe('with argument zeroDeductible', () => {
describe.each([
[false, coverageStatuses.PENDING, 0],
[false, coverageStatuses.PENDING, 500],
[false, coverageStatuses.NO_COVERAGE, 0],
[false, coverageStatuses.NO_COVERAGE, 500],
[true, coverageStatuses.VERIFIED, 0],
[false, coverageStatuses.VERIFIED, 500]
])('with argument zeroDeductible', (expected, status, deductible) => {
[false, false, 0],
[false, false, 500],
[true, true, 0],
[false, true, 500]
])('with argument zeroDeductible', (expected, isVerified, deductible) => {
test(`returns ${expected} when coverageStatus is ${getEnumName(coverageStatuses, status)} and currentDeductible is ${deductible}`, () => {
// Arrange
const initialStore = {
order: {
insuranceCoverage: {
coverageStatus: status
},
currentDeductible: deductible
}
const order = deepClone(defaultOrder);
order.isVerified = isVerified;
order.currentDeductible = deductible;
const mockStoreActions = () => {
useMainStore().getSubmittedOrder = jest.fn().mockImplementation(() => order);
};
const { wrapper } = getMountedComponent(initialStore);
const { wrapper } = getMountedComponent({}, {}, mockStoreActions);
const argument = 'zeroDeductible';
// Act
@ -277,21 +272,18 @@ describe('TPAConfirmation.vue', () => {
});
describe('with argument verifyingCoverage', () => {
describe.each([
[true, coverageStatuses.PENDING],
[true, coverageStatuses.NO_COVERAGE],
[false, coverageStatuses.VERIFIED]
])('with argument zeroDeductible', (expected, status) => {
[true, false],
[false, true]
])('with argument zeroDeductible', (expected, isVerified) => {
test(`returns ${expected} when coverageStatus is ${getEnumName(coverageStatuses, status)}`, () => {
// Arrange
const initialStore = {
order: {
insuranceCoverage: {
coverageStatus: status
},
currentDeductible: 123
}
const order = deepClone(defaultOrder);
order.isVerified = isVerified;
order.currentDeductible = 123;
const mockStoreActions = () => {
useMainStore().getSubmittedOrder = jest.fn().mockImplementation(() => order);
};
const { wrapper } = getMountedComponent(initialStore);
const { wrapper } = getMountedComponent({}, {}, mockStoreActions);
const argument = 'verifyingCoverage';
// Act
@ -304,6 +296,9 @@ describe('TPAConfirmation.vue', () => {
});
});
describe('Navigation', () => {
const mockStoreActions = () => {
useMainStore().getSubmittedOrder = jest.fn().mockImplementation(() => defaultOrder);
};
test('If Advanced flow, forward button action navigates to carrier URL', () => {
// Arrange
const carrierReturnUrl = 'testURL';
@ -312,7 +307,7 @@ describe('TPAConfirmation.vue', () => {
successReturnURL: carrierReturnUrl
}
};
const { wrapper } = getMountedComponent(initialStore);
const { wrapper } = getMountedComponent(initialStore, {}, mockStoreActions);
// Act
wrapper.vm.forwardButtonAction();

View file

@ -127,7 +127,7 @@ export default {
},
setup() {
const mainStore = useMainStore();
const { submittedOrder } = mainStore;
const submittedOrder = mainStore.getSubmittedOrder();
return { mainStore, submittedOrder };
},
computed: {

View file

@ -50,7 +50,7 @@ const routes = [
// Intercept all navigation if a submitted order exists in storage
if (useMainStore().hasSubmittedOrder()) {
if (to.query.issPage !== issPageValues.ENTRY_PAGE) {
return await GoToConfirmationPage(next, useMainStore().submittedOrder);
return await GoToConfirmationPage(next, useMainStore().getSubmittedOrder());
}
}

View file

@ -423,8 +423,7 @@ export const useMainStore = defineStore({
experimentSettings: (state) => state.applicationUser.experiments
.filter((x) => !!x.isActive)
.map((x) => x.settings)
.reduce((r, c) => Object.assign(r, c), {}) ?? {},
submittedOrder: () => JSON.parse(window.sessionStorage.getItem(webStorageConstants.SUBMITTED_ORDER))
.reduce((r, c) => Object.assign(r, c), {}) ?? {}
},
actions:
{
@ -2651,6 +2650,10 @@ export const useMainStore = defineStore({
return window.sessionStorage.getItem(webStorageConstants.SUBMITTED_ORDER) !== null;
},
getSubmittedOrder() {
return JSON.parse(window.sessionStorage.getItem(webStorageConstants.SUBMITTED_ORDER));
},
createSubmittedOrder(submitType) {
if (this.hasSubmittedOrder()) {
return;