Merge remote-tracking branch 'origin/develop' into feature/digital/SSR-1064

This commit is contained in:
Matt Caimi 2024-02-01 13:40:46 -05:00
commit 2935eefde0
6 changed files with 548 additions and 23 deletions

View file

@ -6,7 +6,8 @@ const bailoutCode = Object.freeze({
CoverageStatementInvalidState: 4,
DoNotSeeMyShop: 5,
PricingResponseError: 6,
TPANotEnabled: 7
TPANotEnabled: 7,
RequestCallback: 8
});
export default bailoutCode;

View file

@ -44,6 +44,10 @@ const bailoutMessage = Object.freeze({
TPANotEnabled: () => ({
code: bailoutCode.TPANotEnabled,
message: 'User selected TPA when TPA is not enabled for this client'
}),
RequestCallback: () => ({
code: bailoutCode.RequestCallback,
message: 'User selected option to receive callback from Safelite'
})
});

View file

@ -6,12 +6,11 @@
v-for="copy in splitCopyOnCMSPlaceHolder(textBlockCopy)"
:key="copy">
<span v-if="doesCopyContainRouterLink(copy)">
<textLink
linkType="text"
:text="getRouterLinkDisplayTextFromCopy(copy)"
href="javascript:void(0)"
useLoadingModal
@click-event="navigateWithScenario(getRouterLinkRouteFromCopy(copy))" />
<routerLink
:to="{
query: { issPage: `${getRouterLinkRouteFromCopy(copy)}` },
name: 'root',
}">{{ getRouterLinkDisplayTextFromCopy(copy) }}</routerLink>
</span>
<span v-else-if="doesCopyContainTextLink(copy)">
<textLink

View file

@ -0,0 +1,369 @@
// Components
import tpaConfirmation from '@/layouts/tpa-confirmation/tpa-confirmation.vue';
// Supporting Files
import { getMountOptions } from '@/helpers/unit-test-helper.js';
import { useMainStore } from '@/store/index.js';
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 navigationScenarios from '@/router/router-constants/navigation-scenarios.js';
jest.mock('@/helpers/layout-helper.js', () => jest.fn());
jest.mock('@/helpers/cms-content-helper', () => ({
fetchCmsContentForPage: jest.fn(),
processIfStatements: jest.fn(),
doesCopyContainRouterLink: jest.fn(),
splitCopyOnCMSPlaceHolder: jest.fn().mockImplementation(() => 'test'),
getRouterLinkRouteFromCopy: jest.fn(),
getRouterLinkDisplayTextFromCopy: jest.fn(),
doesCopyContainTextLink: jest.fn()
}));
const mockMixin = {
methods: {
getCmsContent: jest.fn().mockImplementation(() => ''),
setCmsContent: jest.fn()
}
};
const footerStub = {
render: () => {},
methods: {
updateButtonText: jest.fn()
}
};
function getMountedComponent(mainInitialState = {}, initialData = {}, methodToRun = () => {}) {
const mountOptions = getMountOptions({
router: {
navigate: jest.fn()
}
});
mountOptions.global.stubs = {
siteFooter: footerStub
};
const testingPinia = createTestingPinia({
initialState: {
main: mainInitialState
}
});
useMainStore(testingPinia);
methodToRun();
mountOptions.global.plugins = [testingPinia];
mountOptions.mixins = [mockMixin];
mountOptions.data = () => (
initialData
);
const apiResponses = {
supportingItems: []
};
const apiPromise = Promise.resolve(apiResponses);
settleAllPromises.mockImplementation(() => apiPromise);
fetchCmsContentForPage.mockImplementation(() => Promise.resolve());
const wrapper = mount(tpaConfirmation, mountOptions);
return { wrapper };
}
describe('TPAConfirmation.vue', () => {
describe('Rendering', () => {
test('Should render Site Header', () => {
// Arrange
const { wrapper } = getMountedComponent({});
// Act
const siteHeader = wrapper.findComponent({ ref: 'siteHeader' });
// Assert
expect(siteHeader.exists()).toBe(true);
});
test('Should render Vehicle Banner', () => {
// Arrange
const { wrapper } = getMountedComponent({});
// Act
const vehicleBanner = wrapper.findComponent({ ref: 'vehicleBanner' });
// Assert
expect(vehicleBanner.exists()).toBe(true);
});
test('Should render Confirmation Body One', () => {
// Arrange
const { wrapper } = getMountedComponent({});
// Act
const bodyOne = wrapper.findComponent({ ref: 'tpaConfirmationBodyOne' });
// Assert
expect(bodyOne.exists()).toBe(true);
});
test('Should render Confirmation Body Two', () => {
// Arrange
const { wrapper } = getMountedComponent({});
// Act
const bodyTwo = wrapper.findComponent({ ref: 'tpaConfirmationBodyTwo' });
// Assert
expect(bodyTwo.exists()).toBe(true);
});
test('Should render Contact Carrier text', () => {
// Arrange
const { wrapper } = getMountedComponent({});
// Act
const contactCarrierText = wrapper.findComponent({ ref: 'contactCarrierText' });
// Assert
expect(contactCarrierText.exists()).toBe(true);
});
test('Should render Order Details title', () => {
// Arrange
const { wrapper } = getMountedComponent({});
// Act
const orderDetailsTitle = wrapper.findComponent({ ref: 'tpaConfirmationOrderDetailsTitle' });
// Assert
expect(orderDetailsTitle.exists()).toBe(true);
});
test('Should render Order Details body', () => {
// Arrange
const { wrapper } = getMountedComponent({});
// Act
const orderDetailsBody = wrapper.findComponent({ ref: 'tpaConfirmationOrderDetailsBody' });
// Assert
expect(orderDetailsBody.exists()).toBe(true);
});
test('Should render Deductible Box', () => {
// Arrange
const { wrapper } = getMountedComponent({});
// Act
const deductibleBox = wrapper.findComponent({ ref: 'deductibleBox' });
// Assert
expect(deductibleBox.exists()).toBe(true);
});
test('Should render Site Footer', () => {
// Arrange
const { wrapper } = getMountedComponent({});
// Act
const siteFooter = wrapper.findComponent({ ref: 'siteFooter' });
// Assert
expect(siteFooter.exists()).toBe(true);
});
});
describe('Computed properties', () => {
describe('Deductible Box value', () => {
test('Should return "Verifying coverage" when isVerified false', () => {
// Arrange
const initialStore = {
order: {
payment: {
insuranceCoverage: { isVerified: false }
}
}
};
const { wrapper } = getMountedComponent(initialStore);
const expected = 'Verifying coverage';
// Assert
expect(wrapper.vm.deductibleBoxValue).toBe(expected);
});
test('Should return deductible value when isVerified true', () => {
// Arrange
const currentDeductible = '500';
const initialStore = {
order: {
payment: {
insuranceCoverage: { isVerified: true }
},
currentDeductible
}
};
const { wrapper } = getMountedComponent(initialStore);
const notExpected = 'Verifying coverage';
// Assert
expect(wrapper.vm.deductibleBoxValue).not.toBe(notExpected);
});
});
});
describe('Methods', () => {
describe('getCustomValueFromString', () => {
describe('with argument deductibleAboveZero', () => {
test.each([
[false],
[true]
])(
'returns false when isVerified %p and currentDeductible is zero',
(isVerified) => {
// Arrange
const initialStore = {
order: {
payment: {
insuranceCoverage: { isVerified }
},
currentDeductible: 0
}
};
const { wrapper } = getMountedComponent(initialStore);
const argument = 'deductibleAboveZero';
// Act
const result = wrapper.vm.getCustomValueFromString(argument);
// Assert
expect(result).toBe(false);
}
);
test.each([
[true, true],
[false, false]
])(
'returns %p when isVerified %p and currentDeductible is not zero',
(expected, isVerified) => {
// Arrange
const initialStore = {
order: {
payment: {
insuranceCoverage: { isVerified }
},
currentDeductible: 500
}
};
const { wrapper } = getMountedComponent(initialStore);
const argument = 'deductibleAboveZero';
// Act
const result = wrapper.vm.getCustomValueFromString(argument);
// Assert
expect(result).toBe(expected);
}
);
});
describe('with argument zeroDeductible', () => {
test.each([
[true, true],
[false, false]
])(
'returns %p when isVerified is %p currentDeductible is zero',
(expected, isVerified) => {
// Arrange
const initialStore = {
order: {
payment: {
insuranceCoverage: { isVerified }
},
currentDeductible: 0
}
};
const { wrapper } = getMountedComponent(initialStore);
const argument = 'zeroDeductible';
// Act
const result = wrapper.vm.getCustomValueFromString(argument);
// Assert
expect(result).toBe(expected);
}
);
test.each([
[false],
[true]
])(
'returns false when isVerified is %p currentDeductible is not zero',
(isVerified) => {
// Arrange
const initialStore = {
order: {
payment: {
insuranceCoverage: { isVerified }
},
currentDeductible: 250
}
};
const { wrapper } = getMountedComponent(initialStore);
const argument = 'zeroDeductible';
// Act
const result = wrapper.vm.getCustomValueFromString(argument);
// Assert
expect(result).toBe(false);
}
);
});
describe('with argument verifyingCoverage', () => {
test.each([
[true, false],
[false, true]
])(
'with argument verifyingCoverage returns %p when isVerified %p',
(expected, isVerified) => {
// Arrange
const initialStore = {
order: {
payment: {
insuranceCoverage: { isVerified }
},
currentDeductible: 26
}
};
const { wrapper } = getMountedComponent(initialStore);
const argument = 'verifyingCoverage';
// Act
const result = wrapper.vm.getCustomValueFromString(argument);
// Assert
expect(result).toBe(expected);
}
);
});
});
describe('setBailoutInfo', () => {
test('setBailout method is called when routerLink clicked', async () => {
// Arrange
const { wrapper } = getMountedComponent({});
const contactCarrierText = wrapper.get('#contactCarrierText');
// Act
await contactCarrierText.trigger('click');
// Assert
expect(wrapper.vm.mainStore.setBailout).toHaveBeenCalledWith(
wrapper.vm.$router.currentRoute,
bailoutMessage.RequestCallback
);
});
});
// TODO: Add tests for forward navigation to carrier URL - card SSR-1107
describe('Navigation', () => {
// test('Forward button action, navigate forward with CLICKED_FORWARD scenario', () => {
// // Arrange
// const { wrapper } = getMountedComponent({});
// // Act
// wrapper.vm.forwardButtonAction();
// // Assert
// expect(wrapper.vm.$router.navigate)
// .toHaveBeenCalledWith(navigationScenarios.CLICKED_FORWARD);
// });
});
});
});

View file

@ -6,15 +6,59 @@
@invalidSubmit="onInvalidSubmit">
<div class="page-container-grouped-styles">
<div class="fade-on-route-transition position-relative">
<siteHeader cmsWidgetName="SiteHeaderWidget" />
<div class="container-fluid pb-2 confirmation">
<p>Placeholder for tpa-confirmation page</p>
<siteHeader
ref="siteHeader"
cmsWidgetName="SiteHeaderWidget" />
<div class="container-fluid px-5 pb-2 confirmation">
<vehicleBanner
ref="vehicleBanner"
class="mb-4"
cmsWidgetName="VehicleBannerWidget"
:displayGenericVehicleImage="false" />
<div class="text-center text-color--black pb-2 fs-5">
<img :src="tpaConfirmationImage" />
<span class="ms-2" v-html="tpaConfirmationHeaderText"></span>
</div>
<div class="text-center text-color--black mb-3 fw-bold">
<span v-html="tpaConfirmationSubheaderText"></span>
</div>
<textBlock
ref="tpaConfirmationBodyOne"
class="tpa-body-one mt-0"
:customText="tpaConfirmationBodyOne" />
<textBlock
ref="tpaConfirmationBodyTwo"
:customText="tpaConfirmationBodyTwo"
class="small mt-0 mb-4" />
<textBlock
id="contactCarrierText"
ref="contactCarrierText"
:customText="contactCarrierText"
class="contact-carrier-text small"
@click="setBailoutInfo()" />
<div
ref="confirmationOrderDetailsSection">
<textBlock
ref="tpaConfirmationOrderDetailsTitle"
:customText="orderDetailsTitle"
class="text-color--black fw-bold lh-base mt-5 mb-4"
:marginTopSizeOverride="4" />
<textBlock
id="tpaConfirmationOrderDetailsBody"
ref="tpaConfirmationOrderDetailsBody"
:customText="orderDetailsBody"
:marginTopSizeOverride="4"
class="mb-4 small" />
<deductibleBox
ref="deductibleBox"
:value="deductibleBoxValue" />
</div>
<siteFooter
ref="siteFooter"
cmsWidgetName="SiteFooterWidget"
:isForwardActionDisabled="!meta.valid"
@ForwardClicked="forwardButtonAction"
@backClicked="navigateBack" />
ref="siteFooter"
cmsWidgetName="SiteFooterWidget"
:isForwardActionDisabled="!meta.valid"
@ForwardClicked="forwardButtonAction"
@backClicked="navigateBack" />
</div>
</div>
</div>
@ -23,19 +67,30 @@
<script>
// Components
import siteHeader from '@/iss-components/site-header/site-header.vue';
import vehicleBanner from '@/iss-components/vehicle-banner/vehicle-banner.vue';
import siteFooter from '@/iss-components/site-footer/site-footer.vue';
import textBlock from '@/digital-components/text-block/text-block.vue';
import deductibleBox from '@/layouts/tpa-submit/deductible-box/deductible-box.vue';
// Supporting files
import { fetchCmsContentForPage } from '@/helpers/cms-content-helper';
import { fetchCmsContentForPage, processIfStatements } from '@/helpers/cms-content-helper';
import settleAllPromises from '@/helpers/layout-helper';
import { Form } from 'vee-validate';
import BaseFormMixin from '@/mixins/base-form-mixin.js';
import { useMainStore } from '@/store';
import { toTitleCase, toDisplayPhoneNumber, formatAmountInDollars } from '@/helpers/text-helper.js';
import bailoutMessage from '@/constants/bailoutMessage';
const VERIFYING_COVERAGE = 'Verifying coverage';
export default {
name: 'tpa-confirmation',
components: {
siteHeader,
siteFooter,
vehicleBanner,
textBlock,
deductibleBox,
// eslint-disable-next-line vue/no-reserved-component-names
Form
},
@ -59,26 +114,123 @@ export default {
const mainStore = useMainStore();
return { mainStore };
},
data() {
computed: {
tpaConfirmationHeaderText() {
return this.getCmsContent('TPAConfirmationContent', 'HeaderText');
},
tpaConfirmationImage() {
return this.getCmsContent('TPAConfirmationContent', 'Image');
},
tpaConfirmationSubheaderText() {
return this.getCmsContent('TPAConfirmationContent', 'SubheaderText')
?.replaceAll('{custom:glassShop}', this.preferredShopName);
},
tpaConfirmationBodyOne() {
return this.getCmsContent('TPAConfirmationContent', 'BodyText')
?.replaceAll('{custom:phoneNumber}', this.preferredShopPhoneNumber)
?.replaceAll('{custom:glassShop}', this.preferredShopName);
},
tpaConfirmationBodyTwo() {
return this.getCmsContent('TPAConfirmationContent', 'BodyText2');
},
contactCarrierText() {
const contactCarrierText = this.getCmsContent('ContactCarrierContent', 'Text')
?.replaceAll('{custom:carrierPhoneNumber}', this.carrierPhoneNumber);
return this.processIfStatements(contactCarrierText, 'custom', this.getCustomValueFromString);
},
orderDetailsTitle() {
return this.getCmsContent('OrderDetailsContent', 'HeaderText');
},
orderDetailsBody() {
const orderDetailsBodyText = this.getCmsContent('OrderDetailsContent', 'BodyText');
return this.processIfStatements(orderDetailsBodyText, 'custom', this.getCustomValueFromString);
},
deductibleBoxValue() {
return this.isVerified ? this.formatAmountInDollars(this.currentDeductible) : VERIFYING_COVERAGE;
},
currentDeductible() {
return useMainStore().order.currentDeductible;
},
preferredShopName() {
return toTitleCase(useMainStore().order.serviceLocation.provider.companyName);
},
preferredShopPhoneNumber() {
return this.toDisplayPhoneNumber(useMainStore().order.serviceLocation.provider.phoneNumber);
},
isVerified() {
return useMainStore().order.payment.insuranceCoverage.isVerified;
},
// TODO: Replace with actual carrier number when account service is ready
carrierPhoneNumber() {
return '800-000-0000';
},
carrierName() {
return this.mainStore.issConfig.clientName;
},
carrierUrl() {
const url = this.mainStore.issConfig.successReturnURL;
console.log(url);
return url;
}
},
mounted() {
this.$refs.siteFooter.updateButtonText(`Go back to ${this.carrierName}`);
},
methods:
{
async forwardButtonAction() {
return this.navigateForward();
window.location.href = this.carrierUrl;
},
navigateForward() {
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD,
this.$route
);
}
},
getCustomValueFromString(str) {
switch (str) {
case 'deductibleAboveZero':
return this.isVerified && this.currentDeductible !== 0;
case 'zeroDeductible':
return this.isVerified && this.currentDeductible === 0;
case 'verifyingCoverage':
return !this.isVerified;
case 'coverageVerified':
return this.isVerified;
default:
return null;
}
},
setBailoutInfo() {
this.mainStore.setBailout(this.$router.currentRoute, bailoutMessage.RequestCallback);
},
toDisplayPhoneNumber,
formatAmountInDollars,
processIfStatements
}
};
</script>
<style lang="scss" scoped>
.confirmation p{
margin-bottom:0.75rem;
.text-color--black {
color: $black;
}
.tpa-body-one {
:deep(p) {
line-height: map-get($spacers, 5);
font-size: $h6-font-size;
strong {
color: $black;
}
}
}
.contact-carrier-text {
:deep(a) {
font-weight: $font-weight-bold;
}
}
</style>

View file

@ -64,7 +64,7 @@ import vinLocationInformation from '@/layouts/vin-lookup/vin-location-informatio
import vinLookupAlerts from '@/layouts/vin-lookup/vin-lookup-alerts/vin-lookup-alerts.vue';
import vinQuestion from '@/layouts/vin-lookup/vin-question/vin-question.vue';
import bailoutCode from '@/constants/bailoutCode';
import bailoutMessage from "@/constants/bailoutMessage";
import bailoutMessage from '@/constants/bailoutMessage';
export default {
name: 'vin-lookup',