Baseline linting of several additional layout pages.
This commit is contained in:
parent
8c39458d91
commit
8620d3888b
35 changed files with 1283 additions and 1302 deletions
|
|
@ -19,7 +19,7 @@ module.exports = {
|
|||
'object-curly-newline': ['error', { consistent: true }],
|
||||
'function-paren-newline': ['error', 'never'],
|
||||
'operator-linebreak': ['error', 'before'],
|
||||
'implicit-arrow-linebreak': ['error', 'beside'],
|
||||
'implicit-arrow-linebreak': ['off'],
|
||||
'comma-dangle': ['error', 'never'],
|
||||
indent: ['error', 4],
|
||||
'max-len': ['error', { code: 140 }],
|
||||
|
|
|
|||
|
|
@ -19,9 +19,70 @@ jest.mock('@/helpers/cms-content-helper', () => ({
|
|||
fetchCmsContentForPage: jest.fn()
|
||||
}));
|
||||
|
||||
|
||||
const baseStoreGettersPageData = () => {
|
||||
function setupMocks({
|
||||
mountOptionsMockData = {
|
||||
router: {
|
||||
navigate: jest.fn(),
|
||||
navigateWithSaving: jest.fn(),
|
||||
navigateWithoutSaving: jest.fn()
|
||||
},
|
||||
actionList: [
|
||||
{
|
||||
actionName: 'savePartQuestionAnswers',
|
||||
data: {}
|
||||
},
|
||||
{
|
||||
actionName: 'getParts',
|
||||
data: {}
|
||||
}
|
||||
],
|
||||
route: {
|
||||
query: {
|
||||
issPage: 'part-questions'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
computedSwitcher: [
|
||||
{
|
||||
glassLocation: 'Windshield',
|
||||
glassName: 'Single',
|
||||
answerData: {
|
||||
answerResult: 'FW04848',
|
||||
answeredQuestions: []
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
},
|
||||
questionsData: {
|
||||
get() {
|
||||
return this.computedSwitcher;
|
||||
},
|
||||
set(val) {
|
||||
this.computedSwitcher = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
}) {
|
||||
useMainStore().getParts = jest.fn(() => ({
|
||||
data: {
|
||||
glassPieceParts: []
|
||||
}
|
||||
}));
|
||||
|
||||
const mountOptions = getMountOptions({
|
||||
...mountOptionsMockData,
|
||||
mixins: [baseMixin, vehicleQuestionsMixin]
|
||||
});
|
||||
mountOptions.attachTo = document.body;
|
||||
|
||||
const wrapper = shallowMount(partQuestions, mountOptions);
|
||||
|
||||
return { wrapper };
|
||||
}
|
||||
|
||||
const baseStoreGettersPageData = () => ({
|
||||
partsOrQuestions: [
|
||||
{
|
||||
parts: null,
|
||||
|
|
@ -50,10 +111,8 @@ const baseStoreGettersPageData = () => {
|
|||
answerData: null
|
||||
}
|
||||
]
|
||||
};
|
||||
};
|
||||
const baseStoreGettersDamage = () => {
|
||||
return {
|
||||
});
|
||||
const baseStoreGettersDamage = () => ({
|
||||
partsQuestionAnswers: [
|
||||
{
|
||||
glassLocation: 'Windshield',
|
||||
|
|
@ -75,8 +134,7 @@ const baseStoreGettersDamage = () => {
|
|||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
};
|
||||
});
|
||||
|
||||
useMainStore().pageData = baseStoreGettersPageData;
|
||||
useMainStore().damage = baseStoreGettersDamage;
|
||||
|
|
@ -99,9 +157,7 @@ describe('partQuestions.vue...', () => {
|
|||
test('Should return false for valid page requisites if partsOrQuestions in pageData is missing', () => {
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
useMainStore().pageData = jest.fn(() => {
|
||||
return undefined;
|
||||
});
|
||||
useMainStore().pageData = jest.fn(() => undefined);
|
||||
|
||||
// Act
|
||||
const result = wrapper.vm.arePagePrerequisitesValid();
|
||||
|
|
@ -114,11 +170,9 @@ describe('partQuestions.vue...', () => {
|
|||
|
||||
test('Should be at least one item in partsOrQuestions', () => {
|
||||
// Arrange
|
||||
useMainStore().pageData = jest.fn(() => {
|
||||
return {
|
||||
useMainStore().pageData = jest.fn(() => ({
|
||||
partsOrQuestions: []
|
||||
};
|
||||
});
|
||||
}));
|
||||
useMainStore().damage = baseStoreGettersDamage;
|
||||
|
||||
const { wrapper } = setupMocks({});
|
||||
|
|
@ -212,13 +266,11 @@ describe('partQuestions.vue...', () => {
|
|||
]
|
||||
});
|
||||
|
||||
wrapper.vm.getParts = jest.fn(() => {
|
||||
return {
|
||||
wrapper.vm.getParts = jest.fn(() => ({
|
||||
data: {
|
||||
glassPieceParts: []
|
||||
}
|
||||
};
|
||||
});
|
||||
}));
|
||||
|
||||
// Act
|
||||
wrapper.vm.forwardButtonAction();
|
||||
|
|
@ -246,13 +298,11 @@ describe('partQuestions.vue...', () => {
|
|||
}
|
||||
];
|
||||
|
||||
useMainStore().getParts = jest.fn(() => {
|
||||
return {
|
||||
useMainStore().getParts = jest.fn(() => ({
|
||||
data: {
|
||||
glassPieceParts: []
|
||||
}
|
||||
};
|
||||
});
|
||||
}));
|
||||
|
||||
// Act
|
||||
wrapper.vm.forwardButtonAction();
|
||||
|
|
@ -278,13 +328,11 @@ describe('partQuestions.vue...', () => {
|
|||
}
|
||||
}
|
||||
];
|
||||
useMainStore().getParts = jest.fn(() => {
|
||||
return {
|
||||
useMainStore().getParts = jest.fn(() => ({
|
||||
data: {
|
||||
glassPieceParts: []
|
||||
}
|
||||
};
|
||||
});
|
||||
}));
|
||||
|
||||
// Act
|
||||
wrapper.vm.forwardButtonAction();
|
||||
|
|
@ -311,13 +359,11 @@ describe('partQuestions.vue...', () => {
|
|||
}
|
||||
}
|
||||
];
|
||||
useMainStore().getParts = jest.fn(() => {
|
||||
return {
|
||||
useMainStore().getParts = jest.fn(() => ({
|
||||
data: {
|
||||
glassPieceParts: []
|
||||
}
|
||||
};
|
||||
});
|
||||
}));
|
||||
wrapper.vm.navigateForward = jest.fn();
|
||||
|
||||
// Act
|
||||
|
|
@ -330,68 +376,3 @@ describe('partQuestions.vue...', () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
function setupMocks({
|
||||
mountOptionsMockData = {
|
||||
router: {
|
||||
navigate: jest.fn(),
|
||||
navigateWithSaving: jest.fn(),
|
||||
navigateWithoutSaving: jest.fn()
|
||||
},
|
||||
actionList: [
|
||||
{
|
||||
actionName: 'savePartQuestionAnswers',
|
||||
data: {}
|
||||
},
|
||||
{
|
||||
actionName: 'getParts',
|
||||
data: {}
|
||||
}
|
||||
],
|
||||
route: {
|
||||
query: {
|
||||
issPage: 'part-questions'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
computedSwitcher: [
|
||||
{
|
||||
glassLocation: 'Windshield',
|
||||
glassName: 'Single',
|
||||
answerData: {
|
||||
answerResult: 'FW04848',
|
||||
answeredQuestions: []
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
},
|
||||
questionsData: {
|
||||
get() {
|
||||
return this.computedSwitcher;
|
||||
},
|
||||
set(val) {
|
||||
this.computedSwitcher = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
}) {
|
||||
useMainStore().getParts = jest.fn(() => {
|
||||
return {
|
||||
data: {
|
||||
glassPieceParts: []
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
const mountOptions = getMountOptions({
|
||||
...mountOptionsMockData,
|
||||
mixins: [baseMixin, vehicleQuestionsMixin]
|
||||
});
|
||||
mountOptions['attachTo'] = document.body;
|
||||
|
||||
const wrapper = shallowMount(partQuestions, mountOptions);
|
||||
|
||||
return { wrapper };
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,16 +1,20 @@
|
|||
<template>
|
||||
<Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm" v-slot="{ meta }">
|
||||
<Form
|
||||
ref="theForm"
|
||||
v-slot="{ meta }"
|
||||
@submit="onSubmit"
|
||||
@invalid-submit="onInvalidSubmit">
|
||||
<questions-page-layout
|
||||
ref="questionsPageLayout"
|
||||
v-model="selectedAnswers"
|
||||
:isMetaValid="meta.valid"
|
||||
:alertFewMoreQuestionsHeader="AlertFewMoreQuestionsHeader"
|
||||
:alertFewMoreQuestionsCopy="AlertFewMoreQuestionsCopy"
|
||||
:questionsData="questionsData"
|
||||
:validationRules="rules.optionRequired"
|
||||
v-model="selectedAnswers"
|
||||
:index="currentGlassIndex"
|
||||
@forwardButtonAction="forwardButtonAction"
|
||||
@back-click="navigateBack"
|
||||
:index="currentGlassIndex" />
|
||||
@back-click="navigateBack" />
|
||||
</Form>
|
||||
</template>
|
||||
|
||||
|
|
@ -30,6 +34,10 @@ import globalRules from '@/constants/global-rules';
|
|||
|
||||
export default {
|
||||
name: 'part-questions',
|
||||
components: {
|
||||
Form,
|
||||
questionsPageLayout
|
||||
},
|
||||
mixins: [BaseFormMixin, vehicleQuestionsMixin],
|
||||
async beforeRouteEnter(to, from, next) {
|
||||
// Call APIs
|
||||
|
|
@ -80,22 +88,20 @@ export default {
|
|||
.map((glass, index) => {
|
||||
// NOTE: questions for property "questions" can differ between layouts
|
||||
glass.questions = glass.partQuestions;
|
||||
glass.answerKey = glass.glassLocation + '-' + glass.glassName;
|
||||
glass.answerKey = `${glass.glassLocation}-${glass.glassName}`;
|
||||
// reset selectedAnswers for this glass
|
||||
this.selectedAnswers[glass.answerKey] = [];
|
||||
|
||||
const updatedGlass = this.setupInitialData(glass, index, alreadyAnsweredQuestions);
|
||||
|
||||
// Set up watch for each set of glass questions
|
||||
this.$watch(
|
||||
'selectedAnswers.' + glass.answerKey,
|
||||
this.$watch(`selectedAnswers.${glass.answerKey}`,
|
||||
(newValue) => {
|
||||
if (newValue && Object.keys(newValue).length > 0) {
|
||||
this.handleAnswerUpdates(newValue, glass.answerKey);
|
||||
}
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
{ deep: true });
|
||||
|
||||
return updatedGlass;
|
||||
});
|
||||
|
|
@ -104,20 +110,18 @@ export default {
|
|||
arePagePrerequisitesValid() {
|
||||
const partQuestionsFromPageData = useMainStore().pageData(issPageValues.PART_QUESTIONS);
|
||||
return (
|
||||
partQuestionsFromPageData &&
|
||||
Object.keys(partQuestionsFromPageData.partsOrQuestions).length > 0
|
||||
partQuestionsFromPageData
|
||||
&& Object.keys(partQuestionsFromPageData.partsOrQuestions).length > 0
|
||||
);
|
||||
},
|
||||
async forwardButtonAction() {
|
||||
const questionAnswersArray = this.questionsData.map((glass) => {
|
||||
return {
|
||||
const questionAnswersArray = this.questionsData.map((glass) => ({
|
||||
glassLocation: glass.glassLocation,
|
||||
glassName: glass.glassName,
|
||||
result: (glass.answerData && glass.answerData.answerResult) || '',
|
||||
answeredQuestions: glass.answerData?.answeredQuestions,
|
||||
isSuppressedPart: glass.isSuppressedPart
|
||||
};
|
||||
});
|
||||
}));
|
||||
|
||||
// clear out answerData for future page loads; must occur prior to store save
|
||||
this.questionsData.forEach((glass) => {
|
||||
|
|
@ -137,10 +141,6 @@ export default {
|
|||
// TODO KO delete for quote mvp
|
||||
this.navigateForward(glassPartsForStore, null);
|
||||
}
|
||||
},
|
||||
components: {
|
||||
Form,
|
||||
questionsPageLayout
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,17 +1,20 @@
|
|||
<template>
|
||||
<Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm" v-slot="{ meta }" >
|
||||
<Form
|
||||
ref="theForm"
|
||||
v-slot="{ meta }"
|
||||
@submit="onSubmit"
|
||||
@invalid-submit="onInvalidSubmit">
|
||||
<div class="page-container-grouped-styles">
|
||||
<div class="fade-on-route-transition position-relative">
|
||||
<siteHeader cmsWidgetName="SiteHeaderWidget" />
|
||||
<div class="container-fluid pb-2 payment">
|
||||
<p>Placeholder for payment page</p>
|
||||
<siteFooter
|
||||
cmsWidgetName="SiteFooterWidget"
|
||||
ref="siteFooter"
|
||||
cmsWidgetName="SiteFooterWidget"
|
||||
:isForwardActionDisabled="!meta.valid"
|
||||
@ForwardClicked="forwardButtonAction"
|
||||
@back-clicked="backButtonAction"
|
||||
/>
|
||||
@back-clicked="backButtonAction" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -31,14 +34,12 @@ import { useMainStore } from '@/store';
|
|||
|
||||
export default {
|
||||
name: 'payment-page',
|
||||
components: {
|
||||
siteHeader,
|
||||
siteFooter,
|
||||
Form
|
||||
},
|
||||
mixins: [BaseFormMixin],
|
||||
data() {
|
||||
|
||||
},
|
||||
setup() {
|
||||
const mainStore = useMainStore();
|
||||
return { mainStore };
|
||||
},
|
||||
async beforeRouteEnter(to, from, next) {
|
||||
// Call APIs
|
||||
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
|
||||
|
|
@ -51,11 +52,18 @@ export default {
|
|||
}];
|
||||
|
||||
// use resultMap to populate layout content.
|
||||
let resultMap = await settleAllPromises(promiseResultMap);
|
||||
const resultMap = await settleAllPromises(promiseResultMap);
|
||||
|
||||
next((vm) => {
|
||||
vm.setCmsContent(resultMap.cmsContent);
|
||||
});
|
||||
},
|
||||
setup() {
|
||||
const mainStore = useMainStore();
|
||||
return { mainStore };
|
||||
},
|
||||
data() {
|
||||
|
||||
},
|
||||
methods:
|
||||
{
|
||||
|
|
@ -69,17 +77,11 @@ export default {
|
|||
|
||||
navigateForward() {
|
||||
}
|
||||
},
|
||||
components: {
|
||||
siteHeader,
|
||||
siteFooter,
|
||||
Form,
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style lang="scss">
|
||||
<style lang="scss" scoped>
|
||||
.payment p{
|
||||
margin-bottom:0.75rem;
|
||||
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
import policyHolderDetails from '@/layouts/policy-holder-details/policy-holder-details.vue';
|
||||
import policyHolderDetails from '@/layouts/policy-holder-details/policy-holder-details';
|
||||
|
||||
// Supporting files
|
||||
// Supporting files
|
||||
import { shallowMount } from '@vue/test-utils';
|
||||
import { settleAllPromises } from '@/helpers/layout-helper.js';
|
||||
import { fetchCmsContentForPage } from '@/helpers/cms-content-helper';
|
||||
import { getMountOptions } from '@/helpers/unit-test-helper.js';
|
||||
import { useMainStore } from '@/store';
|
||||
import { navigationScenarios } from '@/router/router-constants/navigation-scenarios';
|
||||
|
|
@ -19,6 +18,55 @@ jest.mock('@/helpers/cms-content-helper', () => ({
|
|||
fetchCmsContentForPage: jest.fn()
|
||||
}));
|
||||
|
||||
function setupMocks() {
|
||||
const wrapper = shallowMount(policyHolderDetails,
|
||||
getMountOptions({
|
||||
router: {
|
||||
navigate: jest.fn()
|
||||
},
|
||||
mainStore: {
|
||||
order: {
|
||||
customer: {
|
||||
emailAddress: 'test@test.com'
|
||||
}
|
||||
}
|
||||
}
|
||||
}));
|
||||
const policies = [{
|
||||
vehicles: [
|
||||
{
|
||||
vin: 'TEST_VIN'
|
||||
},
|
||||
{
|
||||
vin: 'TEST_VIN2'
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
useMainStore().getCoveragePolicyInfo = jest.fn().mockImplementation(() => Promise.resolve({
|
||||
data: {
|
||||
policies
|
||||
}
|
||||
}));
|
||||
|
||||
const apiResponses = {
|
||||
policyLookupResponse: {
|
||||
policies
|
||||
}
|
||||
};
|
||||
|
||||
settleAllPromises.mockImplementation(() => apiResponses);
|
||||
|
||||
wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => '');
|
||||
wrapper.vm.setCmsContent = jest.fn();
|
||||
wrapper.vm.$refs.siteFooter.updateButtonText = jest.fn();
|
||||
wrapper.vm.$refs.siteFooter.removeLoader = jest.fn();
|
||||
wrapper.vm.$refs.siteFooter.disableForwardButton = jest.fn();
|
||||
wrapper.vm.$refs.siteFooter.enableForwardAction = jest.fn();
|
||||
|
||||
return { wrapper };
|
||||
}
|
||||
|
||||
describe('policy-holder-details.vue', () => {
|
||||
test('Should render policy-holder-details sub-components (policy holder first name, last name, street address etc.)', async () => {
|
||||
// Arrange
|
||||
|
|
@ -116,65 +164,10 @@ describe('navigation', () => {
|
|||
await wrapper.vm.forwardButtonAction();
|
||||
|
||||
// Assert
|
||||
expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith(
|
||||
navigationScenarios.CLICKED_FORWARD_POLICY_VERIFIED,
|
||||
expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith(navigationScenarios.CLICKED_FORWARD_POLICY_VERIFIED,
|
||||
undefined,
|
||||
{},
|
||||
{},
|
||||
mockvehicles
|
||||
);
|
||||
mockvehicles);
|
||||
});
|
||||
});
|
||||
|
||||
function setupMocks() {
|
||||
const wrapper = shallowMount(
|
||||
policyHolderDetails,
|
||||
getMountOptions({
|
||||
router: {
|
||||
navigate: jest.fn()
|
||||
},
|
||||
mainStore: {
|
||||
order: {
|
||||
customer: {
|
||||
emailAddress: 'test@test.com'
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
);
|
||||
const policies = [{
|
||||
vehicles: [
|
||||
{
|
||||
vin: 'TEST_VIN'
|
||||
},
|
||||
{
|
||||
vin: 'TEST_VIN2'
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
useMainStore().getCoveragePolicyInfo = jest.fn().mockImplementation(() => {
|
||||
return Promise.resolve({
|
||||
data: {
|
||||
policies:policies
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
const apiResponses = {
|
||||
policyLookupResponse:{
|
||||
policies:policies
|
||||
}
|
||||
};
|
||||
|
||||
settleAllPromises.mockImplementation(() => apiResponses);
|
||||
|
||||
wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => '');
|
||||
wrapper.vm.setCmsContent = jest.fn();
|
||||
wrapper.vm.$refs.siteFooter.updateButtonText = jest.fn();
|
||||
wrapper.vm.$refs.siteFooter.removeLoader = jest.fn();
|
||||
wrapper.vm.$refs.siteFooter.disableForwardButton = jest.fn();
|
||||
wrapper.vm.$refs.siteFooter.enableForwardAction = jest.fn();
|
||||
|
||||
return { wrapper };
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,40 +1,49 @@
|
|||
<template>
|
||||
<Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm" v-slot="{ meta }" >
|
||||
<Form
|
||||
ref="theForm"
|
||||
v-slot="{ meta }"
|
||||
@submit="onSubmit"
|
||||
@invalid-submit="onInvalidSubmit">
|
||||
<div class="page-container-grouped-styles">
|
||||
<div class="fade-on-route-transition position-relative">
|
||||
<siteHeader cmsWidgetName="SiteHeaderWidget" />
|
||||
<div class="container-fluid pb-2 px-5">
|
||||
<div class="row mt-4 mb-3">
|
||||
<div class="col">
|
||||
<siteSubHeader cmsWidgetName="SiteSubHeaderWidget" id="sub-header"/>
|
||||
<addressQuestions ref="addressQuestions" v-model="customerQuestions.addressQuestions" includeStreetAddress2="true" id="address-questions-wrapper"/>
|
||||
<siteSubHeader
|
||||
id="sub-header"
|
||||
cmsWidgetName="SiteSubHeaderWidget" />
|
||||
<addressQuestions
|
||||
id="address-questions-wrapper"
|
||||
ref="addressQuestions"
|
||||
v-model="customerQuestions.addressQuestions"
|
||||
includeStreetAddress2="true" />
|
||||
<textboxQuestion
|
||||
ref="policyHolderFirstName"
|
||||
v-model="customerQuestions.firstName"
|
||||
inputId="firstNameField"
|
||||
cmsWidgetName="PolicyholderFirstNameQuestion"
|
||||
v-model="customerQuestions.firstName"
|
||||
isRequired
|
||||
ref="policyHolderFirstName"
|
||||
disableAutoFill
|
||||
:validationRules="rules.firstName" />
|
||||
<textboxQuestion
|
||||
ref="policyHolderLastName"
|
||||
v-model="customerQuestions.lastName"
|
||||
class="mt-4"
|
||||
inputId="lastNameField"
|
||||
cmsWidgetName="PolicyholderLastNameQuestion"
|
||||
v-model="customerQuestions.lastName"
|
||||
isRequired
|
||||
ref="policyHolderLastName"
|
||||
disableAutoFill
|
||||
:validationRules="rules.lastName" />
|
||||
</div>
|
||||
</div>
|
||||
<siteFooter
|
||||
ref="siteFooter"
|
||||
class="mt-5"
|
||||
cmsWidgetName="SiteFooterWidget"
|
||||
ref="siteFooter"
|
||||
:isForwardActionDisabled="!meta.valid"
|
||||
@ForwardClicked="forwardButtonAction"
|
||||
@back-clicked="backButtonAction"
|
||||
/>
|
||||
@back-clicked="backButtonAction" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -58,21 +67,16 @@ import { useMainStore } from '@/store';
|
|||
|
||||
export default {
|
||||
name: 'policy-holder-details',
|
||||
components: {
|
||||
siteHeader,
|
||||
siteSubHeader,
|
||||
textboxQuestion,
|
||||
addressQuestions,
|
||||
siteFooter,
|
||||
// eslint-disable-next-line vue/no-reserved-component-names
|
||||
Form
|
||||
},
|
||||
mixins: [BaseFormMixin],
|
||||
data() {
|
||||
return {
|
||||
customerQuestions: this.getPolicyHolderDetailsFromStore(),
|
||||
vehiclesFound: [],
|
||||
rules: {
|
||||
firstName: globalRules.POLICYHOLDER_FIRST_NAME_REQUIRED,
|
||||
lastName: globalRules.POLICYHOLDER_LAST_NAME_REQUIRED
|
||||
}
|
||||
};
|
||||
},
|
||||
setup() {
|
||||
const mainStore = useMainStore();
|
||||
return { mainStore };
|
||||
},
|
||||
async beforeRouteEnter(to, from, next) {
|
||||
// Call APIs
|
||||
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
|
||||
|
|
@ -86,12 +90,34 @@ export default {
|
|||
];
|
||||
|
||||
// use resultMap to populate layout content.
|
||||
let resultMap = await settleAllPromises(promiseResultMap);
|
||||
const resultMap = await settleAllPromises(promiseResultMap);
|
||||
|
||||
next((vm) => {
|
||||
vm.setCmsContent(resultMap.cmsContent);
|
||||
});
|
||||
},
|
||||
setup() {
|
||||
const mainStore = useMainStore();
|
||||
return { mainStore };
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
customerQuestions: this.getPolicyHolderDetailsFromStore(),
|
||||
vehiclesFound: [],
|
||||
rules: {
|
||||
firstName: globalRules.POLICYHOLDER_FIRST_NAME_REQUIRED,
|
||||
lastName: globalRules.POLICYHOLDER_LAST_NAME_REQUIRED
|
||||
}
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
isCoverageEnabled() {
|
||||
return this.mainStore.issConfig.isCoverageEnabled;
|
||||
},
|
||||
vehiclesCount() {
|
||||
return this.vehiclesFound.length;
|
||||
}
|
||||
},
|
||||
methods:
|
||||
{
|
||||
backButtonAction() {
|
||||
|
|
@ -105,18 +131,14 @@ export default {
|
|||
|
||||
navigateForward() {
|
||||
if (this.vehiclesCount > 0) {
|
||||
this.$router.navigate(
|
||||
this.navigationScenarios.CLICKED_FORWARD_POLICY_VERIFIED,
|
||||
this.$router.navigate(this.navigationScenarios.CLICKED_FORWARD_POLICY_VERIFIED,
|
||||
this.$route,
|
||||
{},
|
||||
{},
|
||||
this.vehiclesFound
|
||||
);
|
||||
this.vehiclesFound);
|
||||
} else {
|
||||
this.$router.navigate(
|
||||
this.navigationScenarios.CLICKED_FORWARD_POLICY_UNVERIFIED,
|
||||
this.$route
|
||||
);
|
||||
this.$router.navigate(this.navigationScenarios.CLICKED_FORWARD_POLICY_UNVERIFIED,
|
||||
this.$route);
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -132,29 +154,13 @@ export default {
|
|||
},
|
||||
firstName: this.mainStore.order.customer.firstName,
|
||||
lastName: this.mainStore.order.customer.lastName
|
||||
};
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isCoverageEnabled() {
|
||||
return this.mainStore.issConfig.isCoverageEnabled;
|
||||
},
|
||||
vehiclesCount() {
|
||||
return this.vehiclesFound.length;
|
||||
}
|
||||
},
|
||||
components: {
|
||||
siteHeader,
|
||||
siteSubHeader,
|
||||
textboxQuestion,
|
||||
addressQuestions,
|
||||
siteFooter,
|
||||
Form
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
<style lang="scss" scoped>
|
||||
#sub-header p {
|
||||
font-size: 16px;
|
||||
line-height: 26px;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,12 @@
|
|||
import policyVehiclesQuestion from '@/layouts/policy-vehicles/policy-vehicles-question/policy-vehicles-question.vue';
|
||||
import policyVehiclesQuestion from '@/layouts/policy-vehicles/policy-vehicles-question/policy-vehicles-question';
|
||||
import { shallowMount } from '@vue/test-utils';
|
||||
|
||||
const mockMixin = {
|
||||
methods: {
|
||||
getCmsContent: jest.fn(() => ['vehicle not listed'])
|
||||
}
|
||||
};
|
||||
|
||||
describe('policy-vehicles-question.vue', () => {
|
||||
test('Selected vehicle is emitted upon selection', async () => {
|
||||
// Arrange
|
||||
|
|
@ -22,11 +28,3 @@ describe('policy-vehicles-question.vue', () => {
|
|||
]);
|
||||
});
|
||||
});
|
||||
|
||||
const mockMixin = {
|
||||
methods: {
|
||||
getCmsContent: jest.fn(() => {
|
||||
return ['vehicle not listed'];
|
||||
})
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
:validationRules="validationRules" />
|
||||
</template>
|
||||
<script>
|
||||
import buttonQuestion from '@/digital-components/button-question/button-question.vue';
|
||||
import buttonQuestion from '@/digital-components/button-question/button-question';
|
||||
|
||||
export default ({
|
||||
name: 'policy-vehicles-question',
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import policyVehicles from '@/layouts/policy-vehicles/policy-vehicles.vue';
|
||||
import policyVehicles from '@/layouts/policy-vehicles/policy-vehicles';
|
||||
import { settleAllPromises } from '@/helpers/layout-helper';
|
||||
import { shallowMount } from '@vue/test-utils';
|
||||
import { getMountOptions } from '@/helpers/unit-test-helper';
|
||||
|
|
@ -9,8 +9,8 @@ import baseMixin from '@/mixins/base-mixin';
|
|||
import { getRandomString, getRandomInt } from '@/helpers/data-generation';
|
||||
import { endorsementOptions } from '@/constants/endorsement-options';
|
||||
import { createTestingPinia } from '@pinia/testing';
|
||||
import { issPageValues } from "@/router/router-constants/issPage-values";
|
||||
import { vehicleSelectionOptions } from "@/constants/vehicle-selection-options";
|
||||
import { issPageValues } from '@/router/router-constants/issPage-values';
|
||||
import { vehicleSelectionOptions } from '@/constants/vehicle-selection-options';
|
||||
|
||||
// Mock fetchCmsContentForPage
|
||||
jest.mock('@/helpers/cms-content-helper', () => ({
|
||||
|
|
@ -27,6 +27,54 @@ jest.mock('@/helpers/layout-helper.js', () => ({
|
|||
settleAllPromises: jest.fn()
|
||||
}));
|
||||
|
||||
const mockMixin = {
|
||||
methods: {
|
||||
getCmsContent: jest.fn()
|
||||
},
|
||||
computed: {
|
||||
dynamicStrings() {
|
||||
return { ROUTER_LINK: 'routerLink:' };
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function setupMocks() {
|
||||
const mountOptions = getMountOptions({
|
||||
router: {
|
||||
navigate: jest.fn()
|
||||
},
|
||||
mixins: [mockMixin],
|
||||
global: {
|
||||
mocks: {
|
||||
$route: {
|
||||
params: {
|
||||
id: 1
|
||||
}
|
||||
},
|
||||
$router: {
|
||||
navigate: jest.fn()
|
||||
}
|
||||
},
|
||||
plugins: [createTestingPinia()]
|
||||
}
|
||||
});
|
||||
|
||||
const apiResponses = {
|
||||
cmsContent: {}
|
||||
};
|
||||
|
||||
settleAllPromises.mockImplementation(() => apiResponses);
|
||||
fetchCmsContentForPage.mockImplementation(() => Promise.resolve());
|
||||
|
||||
const wrapper = shallowMount(policyVehicles, mountOptions);
|
||||
wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => '');
|
||||
wrapper.vm.setCmsContent = jest.fn();
|
||||
wrapper.vm.setCmsContent = baseMixin.methods.setCmsContent;
|
||||
wrapper.vm.$refs.siteFooter.updateButtonText = jest.fn();
|
||||
wrapper.vm.$refs.siteFooter.removeLoader = jest.fn();
|
||||
return { wrapper };
|
||||
}
|
||||
|
||||
describe('policy-vehicles.vue', () => {
|
||||
test('Should navigate to CLICKED_BACK if backButtonAction is run', async () => {
|
||||
// Arrange
|
||||
|
|
@ -48,7 +96,7 @@ describe('policy-vehicles.vue', () => {
|
|||
await wrapper.setData({
|
||||
selectedVehicleVin: vin,
|
||||
policyVehicles: [
|
||||
{ vin: vin },
|
||||
{ vin }
|
||||
],
|
||||
bailout: false
|
||||
});
|
||||
|
|
@ -56,19 +104,19 @@ describe('policy-vehicles.vue', () => {
|
|||
const year = getRandomInt(1998, 2023);
|
||||
const lookupVehicleResponse = {
|
||||
data: {
|
||||
year: year,
|
||||
year
|
||||
}
|
||||
};
|
||||
const store = useMainStore();
|
||||
store.lookupVehicleByVin.mockReturnValue(Promise.resolve(lookupVehicleResponse));
|
||||
|
||||
const expectedInput = {
|
||||
year: year,
|
||||
vin: vin,
|
||||
year,
|
||||
vin,
|
||||
noCoverage: true,
|
||||
deductible: 0,
|
||||
repairWaived: false
|
||||
}
|
||||
};
|
||||
|
||||
// Act
|
||||
await wrapper.vm.forwardButtonAction();
|
||||
|
|
@ -76,12 +124,10 @@ describe('policy-vehicles.vue', () => {
|
|||
// Assert
|
||||
expect(wrapper.vm.bailout).toBeFalsy();
|
||||
expect(store.updateVehicle).toHaveBeenCalledWith(expectedInput);
|
||||
expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith(
|
||||
navigationScenarios.CLICKED_FORWARD_LISTED_VEHICLE,
|
||||
expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith(navigationScenarios.CLICKED_FORWARD_LISTED_VEHICLE,
|
||||
undefined,
|
||||
{},
|
||||
{}
|
||||
);
|
||||
{});
|
||||
});
|
||||
|
||||
test('Error in lookupVehicleByVin call => bailout true and navigate forward with CLICKED_FORWARD_WITH_BAILOUT scenario.', async () => {
|
||||
|
|
@ -102,12 +148,10 @@ describe('policy-vehicles.vue', () => {
|
|||
|
||||
// Assert
|
||||
expect(wrapper.vm.bailout).toBeTruthy();
|
||||
expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith(
|
||||
navigationScenarios.CLICKED_FORWARD_WITH_BAILOUT,
|
||||
expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith(navigationScenarios.CLICKED_FORWARD_WITH_BAILOUT,
|
||||
undefined,
|
||||
{},
|
||||
{}
|
||||
);
|
||||
{});
|
||||
});
|
||||
|
||||
test('vehicle not listed => navigate forward with CLICKED_FORWARD_NON_LISTED_VEHICLE scenario.', async () => {
|
||||
|
|
@ -122,12 +166,10 @@ describe('policy-vehicles.vue', () => {
|
|||
await wrapper.vm.forwardButtonAction();
|
||||
|
||||
// Assert
|
||||
expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith(
|
||||
navigationScenarios.CLICKED_FORWARD_NON_LISTED_VEHICLE,
|
||||
expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith(navigationScenarios.CLICKED_FORWARD_NON_LISTED_VEHICLE,
|
||||
undefined,
|
||||
{},
|
||||
{}
|
||||
);
|
||||
{});
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -209,7 +251,7 @@ describe('policy-vehicles.vue', () => {
|
|||
vin: otherVin
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
// Act
|
||||
const result = policyVehicles.computed.deductibleForSelectedVehicle.call(testValues);
|
||||
|
|
@ -225,11 +267,11 @@ describe('policy-vehicles.vue', () => {
|
|||
selectedVehicleVin: vin,
|
||||
policyVehicles: [
|
||||
{
|
||||
vin: vin,
|
||||
vin,
|
||||
coverages: []
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
// Act
|
||||
const result = policyVehicles.computed.deductibleForSelectedVehicle.call(testValues);
|
||||
|
|
@ -247,7 +289,7 @@ describe('policy-vehicles.vue', () => {
|
|||
selectedVehicleVin: vin,
|
||||
policyVehicles: [
|
||||
{
|
||||
vin: vin,
|
||||
vin,
|
||||
coverages: [
|
||||
{
|
||||
deductible: firstDeductible
|
||||
|
|
@ -258,7 +300,7 @@ describe('policy-vehicles.vue', () => {
|
|||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
// Act
|
||||
const result = policyVehicles.computed.deductibleForSelectedVehicle.call(testValues);
|
||||
|
|
@ -280,7 +322,7 @@ describe('policy-vehicles.vue', () => {
|
|||
vin: otherVin
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
// Act
|
||||
const result = policyVehicles.computed.repairWaivedForSelectedVehicle.call(testValues);
|
||||
|
|
@ -296,11 +338,11 @@ describe('policy-vehicles.vue', () => {
|
|||
selectedVehicleVin: vin,
|
||||
policyVehicles: [
|
||||
{
|
||||
vin: vin,
|
||||
vin,
|
||||
endorsements: []
|
||||
}
|
||||
],
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
// Act
|
||||
const result = policyVehicles.computed.repairWaivedForSelectedVehicle.call(testValues);
|
||||
|
|
@ -316,11 +358,11 @@ describe('policy-vehicles.vue', () => {
|
|||
selectedVehicleVin: vin,
|
||||
policyVehicles: [
|
||||
{
|
||||
vin: vin,
|
||||
vin,
|
||||
endorsements: [endorsementOptions.EDUCATOR, endorsementOptions.PARKING_GUARD]
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
// Act
|
||||
const result = policyVehicles.computed.repairWaivedForSelectedVehicle.call(testValues);
|
||||
|
|
@ -336,7 +378,7 @@ describe('policy-vehicles.vue', () => {
|
|||
selectedVehicleVin: vin,
|
||||
policyVehicles: [
|
||||
{
|
||||
vin: vin,
|
||||
vin,
|
||||
endorsements: [
|
||||
endorsementOptions.EDUCATOR,
|
||||
endorsementOptions.REPAIR_WAIVED,
|
||||
|
|
@ -344,7 +386,7 @@ describe('policy-vehicles.vue', () => {
|
|||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
// Act
|
||||
const result = policyVehicles.computed.repairWaivedForSelectedVehicle.call(testValues);
|
||||
|
|
@ -359,7 +401,7 @@ describe('policy-vehicles.vue', () => {
|
|||
const vin = getRandomString(17, 17);
|
||||
useMainStore().applicationUser = {
|
||||
pageData: {
|
||||
[issPageValues.POLICY_VEHICLES]: [{ vin: vin }],
|
||||
[issPageValues.POLICY_VEHICLES]: [{ vin }]
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -372,51 +414,3 @@ describe('policy-vehicles.vue', () => {
|
|||
expect(wrapper.vm.selectedVehicleVin).toBe(vin);
|
||||
});
|
||||
});
|
||||
|
||||
const mockMixin = {
|
||||
methods: {
|
||||
getCmsContent: jest.fn()
|
||||
},
|
||||
computed: {
|
||||
dynamicStrings() {
|
||||
return { ROUTER_LINK: 'routerLink:' };
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function setupMocks() {
|
||||
const mountOptions = getMountOptions({
|
||||
router: {
|
||||
navigate: jest.fn()
|
||||
},
|
||||
mixins: [mockMixin],
|
||||
global: {
|
||||
mocks: {
|
||||
$route: {
|
||||
params: {
|
||||
id: 1
|
||||
}
|
||||
},
|
||||
$router: {
|
||||
navigate: jest.fn()
|
||||
}
|
||||
},
|
||||
plugins: [createTestingPinia()]
|
||||
}
|
||||
});
|
||||
|
||||
const apiResponses = {
|
||||
cmsContent: {}
|
||||
};
|
||||
|
||||
settleAllPromises.mockImplementation(() => apiResponses);
|
||||
fetchCmsContentForPage.mockImplementation(() => Promise.resolve());
|
||||
|
||||
const wrapper = shallowMount(policyVehicles, mountOptions);
|
||||
wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => '');
|
||||
wrapper.vm.setCmsContent = jest.fn();
|
||||
wrapper.vm.setCmsContent = baseMixin.methods.setCmsContent;
|
||||
wrapper.vm.$refs.siteFooter.updateButtonText = jest.fn();
|
||||
wrapper.vm.$refs.siteFooter.removeLoader = jest.fn();
|
||||
return { wrapper };
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,113 +1,6 @@
|
|||
import { mount } from '@vue/test-utils';
|
||||
import providerPrefRadio from './provider-pref-radio';
|
||||
import inputButtonWrapperMixin from '@/mixins/input-button-wrapper-mixin';
|
||||
|
||||
describe('provider-pref-radio.vue', () => {
|
||||
it('Should include buttonLabel in html', async () => {
|
||||
// Arrange
|
||||
let { wrapper } = setupMocks({
|
||||
mountOptionsMockData: {
|
||||
propsData: mockProps,
|
||||
}
|
||||
});
|
||||
|
||||
// Act
|
||||
const outputHtml = wrapper.html();
|
||||
console.log(outputHtml);
|
||||
// Assert
|
||||
expect(outputHtml).toEqual(expect.stringContaining(mockProps['buttonLabel']));
|
||||
});
|
||||
|
||||
it('Should include buttonLabelAuxillaryCopy in html', async () => {
|
||||
// Arrange
|
||||
let { wrapper } = setupMocks({
|
||||
mountOptionsMockData: {
|
||||
propsData: mockProps,
|
||||
}
|
||||
});
|
||||
|
||||
// Act
|
||||
const outputHtml = wrapper.html();
|
||||
|
||||
// Assert
|
||||
expect(outputHtml).toEqual(expect.stringContaining(mockProps['buttonLabelAuxillaryCopy']));
|
||||
});
|
||||
|
||||
it('Should include buttonLabelSubCopy in html', async () => {
|
||||
// Arrange
|
||||
let { wrapper } = setupMocks({
|
||||
mountOptionsMockData: {
|
||||
propsData: mockProps,
|
||||
}
|
||||
});
|
||||
|
||||
// Act
|
||||
const outputHtml = wrapper.html();
|
||||
|
||||
// Assert
|
||||
expect(outputHtml).toEqual(expect.stringContaining(mockProps['buttonLabelSubCopy']));
|
||||
});
|
||||
it('Should include buttonFooterCopy in html', async () => {
|
||||
// Arrange
|
||||
let { wrapper } = setupMocks({
|
||||
mountOptionsMockData: {
|
||||
propsData: mockProps,
|
||||
}
|
||||
});
|
||||
|
||||
// Act
|
||||
const outputHtml = wrapper.html();
|
||||
|
||||
// Assert
|
||||
expect(outputHtml).toEqual(expect.stringContaining(mockProps['buttonFooterCopy']));
|
||||
});
|
||||
it('Should get 5 strings from getArrayOfListItemsFromRawCmsCopy when provided with a dashed (x5) buttonBodyCopy', async () => {
|
||||
// Arrange
|
||||
let { wrapper } = setupMocks({
|
||||
mountOptionsMockData: {
|
||||
propsData: mockProps,
|
||||
}
|
||||
});
|
||||
// Act
|
||||
const results = wrapper.vm.getArrayOfListItemsFromRawCmsCopy(wrapper.vm.buttonBodyCopy);
|
||||
|
||||
// Assert
|
||||
expect(results.length).toBe(5);
|
||||
});
|
||||
it('Should get strings from getArrayOfListItemsFromRawCmsCopy without dashes when provided with a dashed buttonBodyCopy', async () => {
|
||||
// Arrange
|
||||
let { wrapper } = setupMocks({
|
||||
mountOptionsMockData: {
|
||||
propsData: mockProps,
|
||||
}
|
||||
});
|
||||
|
||||
// Act
|
||||
const results = wrapper.vm.getArrayOfListItemsFromRawCmsCopy(wrapper.vm.buttonBodyCopy);
|
||||
|
||||
// Assert
|
||||
const fileredResults = results.filter((result) => {
|
||||
return result.includes(' -');
|
||||
});
|
||||
expect(fileredResults.length).toBe(0);
|
||||
});
|
||||
it('Should get 5 strings from getArrayOfListItemsFromRawCmsCopy when buttonBodyCopy has 6 total dashes, but one is empty ', async () => {
|
||||
// Arrange
|
||||
const moddedProps = mockProps;
|
||||
moddedProps['buttonBodyCopy'] = '- buttonBodyCopy test copy - 2 - 3 - 4 - 5 -';
|
||||
let { wrapper } = setupMocks({
|
||||
mountOptionsMockData: {
|
||||
propsData: moddedProps
|
||||
}
|
||||
});
|
||||
|
||||
// Act
|
||||
const results = wrapper.vm.getArrayOfListItemsFromRawCmsCopy(wrapper.vm.buttonBodyCopy);
|
||||
|
||||
// Assert
|
||||
expect(results.length).toBe(5);
|
||||
});
|
||||
});
|
||||
import providerPrefRadio from './provider-pref-radio';
|
||||
|
||||
const mockProps = {
|
||||
buttonLabel: 'buttonLabel test copy',
|
||||
|
|
@ -125,3 +18,109 @@ function setupMocks({ mountOptionsMockData = {} }) {
|
|||
|
||||
return { wrapper };
|
||||
}
|
||||
|
||||
describe('provider-pref-radio.vue', () => {
|
||||
it('Should include buttonLabel in html', async () => {
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({
|
||||
mountOptionsMockData: {
|
||||
propsData: mockProps
|
||||
}
|
||||
});
|
||||
|
||||
// Act
|
||||
const outputHtml = wrapper.html();
|
||||
console.log(outputHtml);
|
||||
// Assert
|
||||
expect(outputHtml).toEqual(expect.stringContaining(mockProps.buttonLabel));
|
||||
});
|
||||
|
||||
it('Should include buttonLabelAuxillaryCopy in html', async () => {
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({
|
||||
mountOptionsMockData: {
|
||||
propsData: mockProps
|
||||
}
|
||||
});
|
||||
|
||||
// Act
|
||||
const outputHtml = wrapper.html();
|
||||
|
||||
// Assert
|
||||
expect(outputHtml).toEqual(expect.stringContaining(mockProps.buttonLabelAuxillaryCopy));
|
||||
});
|
||||
|
||||
it('Should include buttonLabelSubCopy in html', async () => {
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({
|
||||
mountOptionsMockData: {
|
||||
propsData: mockProps
|
||||
}
|
||||
});
|
||||
|
||||
// Act
|
||||
const outputHtml = wrapper.html();
|
||||
|
||||
// Assert
|
||||
expect(outputHtml).toEqual(expect.stringContaining(mockProps.buttonLabelSubCopy));
|
||||
});
|
||||
it('Should include buttonFooterCopy in html', async () => {
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({
|
||||
mountOptionsMockData: {
|
||||
propsData: mockProps
|
||||
}
|
||||
});
|
||||
|
||||
// Act
|
||||
const outputHtml = wrapper.html();
|
||||
|
||||
// Assert
|
||||
expect(outputHtml).toEqual(expect.stringContaining(mockProps.buttonFooterCopy));
|
||||
});
|
||||
it('Should get 5 strings from getArrayOfListItemsFromRawCmsCopy when provided with a dashed (x5) buttonBodyCopy', async () => {
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({
|
||||
mountOptionsMockData: {
|
||||
propsData: mockProps
|
||||
}
|
||||
});
|
||||
// Act
|
||||
const results = wrapper.vm.getArrayOfListItemsFromRawCmsCopy(wrapper.vm.buttonBodyCopy);
|
||||
|
||||
// Assert
|
||||
expect(results.length).toBe(5);
|
||||
});
|
||||
it('Should get strings from getArrayOfListItemsFromRawCmsCopy without dashes when provided with a dashed buttonBodyCopy', async () => {
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({
|
||||
mountOptionsMockData: {
|
||||
propsData: mockProps
|
||||
}
|
||||
});
|
||||
|
||||
// Act
|
||||
const results = wrapper.vm.getArrayOfListItemsFromRawCmsCopy(wrapper.vm.buttonBodyCopy);
|
||||
|
||||
// Assert
|
||||
const fileredResults = results.filter((result) => result.includes(' -'));
|
||||
expect(fileredResults.length).toBe(0);
|
||||
});
|
||||
it('Should get 5 strings from getArrayOfListItemsFromRawCmsCopy when buttonBodyCopy has 6 total dashes, but one is empty ',
|
||||
async () => {
|
||||
// Arrange
|
||||
const moddedProps = mockProps;
|
||||
moddedProps.buttonBodyCopy = '- buttonBodyCopy test copy - 2 - 3 - 4 - 5 -';
|
||||
const { wrapper } = setupMocks({
|
||||
mountOptionsMockData: {
|
||||
propsData: moddedProps
|
||||
}
|
||||
});
|
||||
|
||||
// Act
|
||||
const results = wrapper.vm.getArrayOfListItemsFromRawCmsCopy(wrapper.vm.buttonBodyCopy);
|
||||
|
||||
// Assert
|
||||
expect(results.length).toBe(5);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,19 +1,28 @@
|
|||
<template>
|
||||
<baseInputButton v-bind="$props" v-model="selectedValue">
|
||||
<div class="option-label"
|
||||
:class="[this.buttonLabelSubCopy ? 'has-subheader' : '']"
|
||||
<baseInputButton
|
||||
v-bind="$props"
|
||||
v-model="selectedValue">
|
||||
<div
|
||||
class="option-label"
|
||||
:class="[buttonLabelSubCopy ? 'has-subheader' : '']"
|
||||
for="testradio">
|
||||
<div class="option-specs">
|
||||
<p class="m-0">
|
||||
<span v-html="this.buttonLabel"></span>
|
||||
<span class="option-info" v-html="this.buttonAuxiliaryCopy"></span>
|
||||
<span v-html="buttonLabel"></span>
|
||||
<span
|
||||
class="option-info"
|
||||
v-html="buttonAuxiliaryCopy"></span>
|
||||
</p>
|
||||
<p class="sub-label m-0"
|
||||
v-if="this.buttonLabelSubCopy"
|
||||
v-html="this.buttonLabelSubCopy"></p>
|
||||
<p
|
||||
v-if="buttonLabelSubCopy"
|
||||
class="sub-label m-0"
|
||||
v-html="buttonLabelSubCopy"></p>
|
||||
<div>
|
||||
<ul>
|
||||
<li v-for="listItem in this.arrayOfListItemsFromBodyText" :key="listItem" class="mb-0">
|
||||
<li
|
||||
v-for="listItem in arrayOfListItemsFromBodyText"
|
||||
:key="listItem"
|
||||
class="mb-0">
|
||||
<!-- no textLink -->
|
||||
<span v-html="listItem"></span>
|
||||
</li>
|
||||
|
|
@ -26,16 +35,14 @@
|
|||
|
||||
<script>
|
||||
import baseInputButton from '@/digital-components/base-input-button/base-input-button';
|
||||
import textLink from '@/ux-components/text-link/text-link';
|
||||
import inputButtonWrapperMixin from '@/mixins/input-button-wrapper-mixin';
|
||||
|
||||
export default {
|
||||
name: 'providerPrefRadio',
|
||||
mixins: [inputButtonWrapperMixin],
|
||||
name: 'provider-pref-radio',
|
||||
components: {
|
||||
baseInputButton,
|
||||
textLink
|
||||
baseInputButton
|
||||
},
|
||||
mixins: [inputButtonWrapperMixin],
|
||||
computed: {
|
||||
arrayOfListItemsFromBodyText() {
|
||||
return this.getArrayOfListItemsFromRawCmsCopy(this.buttonBodyCopy);
|
||||
|
|
@ -48,6 +55,7 @@ export default {
|
|||
.split('- ') // At some point we'll want a better delimiter
|
||||
.filter((lineItem) => lineItem);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import ProviderPreference from '@/layouts/provider-preference/provider-preference.vue'
|
||||
import ProviderPreference from '@/layouts/provider-preference/provider-preference';
|
||||
|
||||
import { shallowMount } from '@vue/test-utils';
|
||||
import { settleAllPromises } from '@/helpers/layout-helper.js';
|
||||
import { fetchCmsContentForPage, setupModalLinks } from '@/helpers/cms-content-helper';
|
||||
import { fetchCmsContentForPage } from '@/helpers/cms-content-helper';
|
||||
import { getMountOptions } from '@/helpers/unit-test-helper.js';
|
||||
import { useMainStore } from '@/store';
|
||||
import { navigationScenarios } from '@/router/router-constants/navigation-scenarios';
|
||||
|
|
@ -18,6 +18,29 @@ jest.mock('@/helpers/cms-content-helper', () => ({
|
|||
setupModalLinks: jest.fn()
|
||||
}));
|
||||
|
||||
function setupMocks(mockApiResponses) {
|
||||
const mountOptions = getMountOptions({
|
||||
router: {
|
||||
navigate: jest.fn()
|
||||
},
|
||||
route: 'provider-preference'
|
||||
});
|
||||
|
||||
const wrapper = shallowMount(ProviderPreference,
|
||||
mountOptions);
|
||||
|
||||
useMainStore().getCoveragePolicyInfo = jest.fn().mockImplementation(() => Promise.resolve({
|
||||
data: {}
|
||||
}));
|
||||
|
||||
const apiResponses = mockApiResponses;
|
||||
|
||||
settleAllPromises.mockImplementation(() => apiResponses);
|
||||
fetchCmsContentForPage.mockImplementation(() => { });
|
||||
|
||||
return { wrapper };
|
||||
}
|
||||
|
||||
describe('provider-preference.vue', () => {
|
||||
test('Should navigate to safelite flow when safelite selected', () => {
|
||||
// Arrange
|
||||
|
|
@ -57,30 +80,3 @@ describe('provider-preference.vue', () => {
|
|||
expect(wrapper.vm.$router.navigate).toBeCalledWith(navigationScenarios.CLICKED_FORWARD_WITH_TPA_DISABLED, 'provider-preference');
|
||||
});
|
||||
});
|
||||
|
||||
function setupMocks(mockApiResponses) {
|
||||
const mountOptions = getMountOptions({
|
||||
router: {
|
||||
navigate: jest.fn()
|
||||
},
|
||||
route: 'provider-preference'
|
||||
});
|
||||
|
||||
const wrapper = shallowMount(
|
||||
ProviderPreference,
|
||||
mountOptions
|
||||
);
|
||||
|
||||
useMainStore().getCoveragePolicyInfo = jest.fn().mockImplementation(() => {
|
||||
return Promise.resolve({
|
||||
data: {}
|
||||
})
|
||||
})
|
||||
|
||||
const apiResponses = mockApiResponses;
|
||||
|
||||
settleAllPromises.mockImplementation(() => apiResponses);
|
||||
fetchCmsContentForPage.mockImplementation (() => {});
|
||||
|
||||
return { wrapper };
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,52 +1,60 @@
|
|||
<template>
|
||||
<Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm">
|
||||
<Form
|
||||
ref="theForm"
|
||||
@submit="onSubmit"
|
||||
@invalid-submit="onInvalidSubmit">
|
||||
<div class="page-container-grouped-styles">
|
||||
<div class="fade-on-route-transition position-relative">
|
||||
<siteHeader cmsWidgetName="SiteHeaderWidget" />
|
||||
<siteSubHeader cmsWidgetName="SiteSubHeader" id="sub-header" class="mb-5 mt-4" />
|
||||
|
||||
<buttonQuestion ref="buttonQuestion"
|
||||
<siteSubHeader
|
||||
id="sub-header"
|
||||
cmsWidgetName="SiteSubHeader"
|
||||
class="mb-5 mt-4" />
|
||||
<buttonQuestion
|
||||
ref="buttonQuestion"
|
||||
v-model="selectedProvider"
|
||||
questionText="Select an option:"
|
||||
:answers="prefAnswers"
|
||||
groupName="prefQuestions"
|
||||
buttonTypeString="providerPrefRadio"
|
||||
v-model="selectedProvider"
|
||||
:validationRules="rules.optionRequired"
|
||||
isRequired
|
||||
class="mx-5" />
|
||||
<div class="px-5">
|
||||
<siteFooter
|
||||
ref="siteFooter"
|
||||
class="mt-5"
|
||||
cmsWidgetName="SiteFooterWidget"
|
||||
:isForwardActionDisabled="isForwardActionDisabled"
|
||||
@backClicked="backButtonAction"
|
||||
@forwardClicked="forwardButtonAction"
|
||||
ref="siteFooter" />
|
||||
@forwardClicked="forwardButtonAction" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<recalModal ref="recalModal" cmsWidgetName="RecalModal" />
|
||||
<steeringModal cmsWidgetName="StateSteeringModal" ref="StateSteeringModal" />
|
||||
<recalModal
|
||||
ref="recalModal"
|
||||
cmsWidgetName="RecalModal" />
|
||||
<steeringModal
|
||||
ref="StateSteeringModal"
|
||||
cmsWidgetName="StateSteeringModal" />
|
||||
<shopPreferenceModal
|
||||
cmsWidgetName="ShopPreferenceDrawer"
|
||||
ref="ShopPreferenceDrawer"
|
||||
@openSteering="openStateSteeringModal"
|
||||
:showSteeringLink="showSteeringLink"/>
|
||||
<tpaRecalModal cmsWidgetName="TPARecalModal"
|
||||
cmsWidgetName="ShopPreferenceDrawer"
|
||||
:showSteeringLink="showSteeringLink"
|
||||
@openSteering="openStateSteeringModal" />
|
||||
<tpaRecalModal
|
||||
ref="TPARecalModal"
|
||||
cmsWidgetName="TPARecalModal"
|
||||
:ackError="ackError"
|
||||
@buttonClick="navigateWithTPAAck"
|
||||
/>
|
||||
@buttonClick="navigateWithTPAAck" />
|
||||
</Form>
|
||||
|
||||
</template>
|
||||
<script>
|
||||
// Import Supporting Files
|
||||
import { fetchCmsContentForPage, setupModalLinks, processIfStatements } from '@/helpers/cms-content-helper';
|
||||
import { fetchCmsContentForPage, setupModalLinks } from '@/helpers/cms-content-helper';
|
||||
import { settleAllPromises } from '@/helpers/layout-helper';
|
||||
import { errorMessages } from '@/constants/error-messages';
|
||||
import buttonQuestion from '@/digital-components/button-question/button-question';
|
||||
import contentGroupModal from '@/iss-components/content-group-modal/content-group-modal';
|
||||
import { issPageValues } from '@/router/router-constants/issPage-values';
|
||||
|
||||
// Import Component
|
||||
|
|
@ -55,42 +63,30 @@ import { Form } from 'vee-validate';
|
|||
import siteFooter from '@/iss-components/site-footer/site-footer';
|
||||
import siteHeader from '@/iss-components/site-header/site-header';
|
||||
import siteSubHeader from '@/iss-components/site-sub-header/site-sub-header';
|
||||
import providerPrefRadio from './provider-pref-radio/provider-pref-radio';
|
||||
import recalModal from '@/layouts/coverage-statement/recal-modal/recal-modal';
|
||||
import steeringModal from '@/layouts/provider-preference/steering-modal/steering-modal';
|
||||
import shopPreferenceModal from '@/layouts/provider-preference/shop-preference-modal/shop-preference-modal';
|
||||
import tpaRecalModal from '@/layouts/provider-preference/tpa-recal-modal/tpa-recal-modal.vue'
|
||||
import tpaRecalModal from '@/layouts/provider-preference/tpa-recal-modal/tpa-recal-modal';
|
||||
import globalRules from '@/constants/global-rules';
|
||||
|
||||
const options = { SAFELITE: 'SafeliteOption', TPA: 'TPAOption' };
|
||||
|
||||
export default {
|
||||
name: 'provider-preference',
|
||||
mixins: [baseFormMixin],
|
||||
|
||||
components: {
|
||||
siteFooter,
|
||||
siteHeader,
|
||||
siteSubHeader,
|
||||
// eslint-disable-next-line vue/no-reserved-component-names
|
||||
Form,
|
||||
buttonQuestion,
|
||||
contentGroupModal,
|
||||
providerPrefRadio,
|
||||
recalModal,
|
||||
steeringModal,
|
||||
shopPreferenceModal,
|
||||
tpaRecalModal
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
selectedProvider: null,
|
||||
showSteeringLink: false,
|
||||
tpaAcknowledgement: false,
|
||||
rules: {
|
||||
optionRequired: globalRules.OPTION_REQUIRED
|
||||
}
|
||||
};
|
||||
},
|
||||
mixins: [baseFormMixin],
|
||||
async beforeRouteEnter(to, from, next) {
|
||||
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
|
||||
// Settle promises and get results
|
||||
|
|
@ -110,6 +106,16 @@ export default {
|
|||
}
|
||||
});
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
selectedProvider: null,
|
||||
showSteeringLink: false,
|
||||
tpaAcknowledgement: false,
|
||||
rules: {
|
||||
optionRequired: globalRules.OPTION_REQUIRED
|
||||
}
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
isForwardActionDisabled() {
|
||||
return this.selectedProvider === null;
|
||||
|
|
@ -140,6 +146,12 @@ export default {
|
|||
return errorMessages.ACKNOWLEDGEMENT_REQUIRED;
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
setupModalLinks(this);
|
||||
const pageData = this.mainStore.pageData(issPageValues.PROVIDER_PREFERENCE);
|
||||
this.selectedProvider = pageData?.selectedProvider ? pageData.selectedProvider : null;
|
||||
this.tpaAcknowledgement = pageData?.tpaAcknowledgement ? pageData.tpaAcknowledgement : false;
|
||||
},
|
||||
methods: {
|
||||
getHeaderTextFromCms(cmsWidgetName) {
|
||||
const headerText = this.getCmsContent(cmsWidgetName, 'HeaderText');
|
||||
|
|
@ -161,7 +173,10 @@ export default {
|
|||
this.$router.navigate(scenario, this.$route);
|
||||
},
|
||||
navigateWithTPAAck() {
|
||||
this.mainStore.saveProviderPreferenceData({selectedProvider: this.selectedProvider, tpaAcknowledgement: this.tpaAcknowledgement});
|
||||
this.mainStore.saveProviderPreferenceData({
|
||||
selectedProvider: this.selectedProvider,
|
||||
tpaAcknowledgement: this.tpaAcknowledgement
|
||||
});
|
||||
this.navigateForward(this.navigationScenarios.CLICKED_FORWARD_WITH_TPA_ENABLED);
|
||||
},
|
||||
forwardButtonAction() {
|
||||
|
|
@ -183,24 +198,22 @@ export default {
|
|||
scenario = this.navigationScenarios.CLICKED_FORWARD_WITH_TPA_DISABLED;
|
||||
}
|
||||
break;
|
||||
};
|
||||
default:
|
||||
}
|
||||
this.navigateForward(scenario);
|
||||
this.mainStore.saveProviderPreferenceData({selectedProvider: this.selectedProvider, tpaAcknowledgement: this.tpaAcknowledgement});
|
||||
this.mainStore.saveProviderPreferenceData({
|
||||
selectedProvider: this.selectedProvider,
|
||||
tpaAcknowledgement: this.tpaAcknowledgement
|
||||
});
|
||||
}
|
||||
},
|
||||
openStateSteeringModal() {
|
||||
this.$refs.StateSteeringModal.openModal();
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
setupModalLinks(this);
|
||||
const pageData = this.mainStore.pageData(issPageValues.PROVIDER_PREFERENCE);
|
||||
this.selectedProvider = pageData?.selectedProvider ? pageData.selectedProvider : null;
|
||||
this.tpaAcknowledgement = pageData?.tpaAcknowledgement ? pageData.tpaAcknowledgement : false;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" >
|
||||
<style lang="scss" scoped>
|
||||
#sub-header span{
|
||||
color: $black;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
import shopPreferenceModal from './shop-preference-modal.vue'
|
||||
|
||||
import { shallowMount } from '@vue/test-utils';
|
||||
import { settleAllPromises } from '@/helpers/layout-helper.js';
|
||||
import { fetchCmsContentForPage, setupModalLinks } from '@/helpers/cms-content-helper';
|
||||
import { fetchCmsContentForPage } from '@/helpers/cms-content-helper';
|
||||
import { getMountOptions } from '@/helpers/unit-test-helper.js';
|
||||
import shopPreferenceModal from './shop-preference-modal';
|
||||
|
||||
// Mock our module for promises.
|
||||
jest.mock('@/helpers/layout-helper.js', () => ({
|
||||
|
|
@ -16,6 +15,26 @@ jest.mock('@/helpers/cms-content-helper', () => ({
|
|||
setupModalLinks: jest.fn()
|
||||
}));
|
||||
|
||||
function setupMocks(propsData) {
|
||||
const mountOptions = getMountOptions({
|
||||
router: {
|
||||
navigate: jest.fn()
|
||||
}
|
||||
});
|
||||
|
||||
mountOptions.propsData = propsData;
|
||||
|
||||
const wrapper = shallowMount(shopPreferenceModal,
|
||||
mountOptions);
|
||||
|
||||
const apiResponses = {};
|
||||
|
||||
settleAllPromises.mockImplementation(() => apiResponses);
|
||||
fetchCmsContentForPage.mockImplementation(() => { });
|
||||
|
||||
return { wrapper };
|
||||
}
|
||||
|
||||
describe('provider-preference.vue', () => {
|
||||
test('Should display state specific steering modal link when in state with steering language', async () => {
|
||||
// Arrange
|
||||
|
|
@ -25,7 +44,6 @@ describe('provider-preference.vue', () => {
|
|||
|
||||
// Test
|
||||
expect(wrapper.vm.showSteeringLink).toBeTruthy();
|
||||
|
||||
});
|
||||
|
||||
test('Should not display state specific steering modal link when not in state with steering language', async () => {
|
||||
|
|
@ -38,25 +56,3 @@ describe('provider-preference.vue', () => {
|
|||
expect(wrapper.vm.showSteeringLink).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
function setupMocks(propsData) {
|
||||
const mountOptions = getMountOptions({
|
||||
router: {
|
||||
navigate: jest.fn()
|
||||
}
|
||||
});
|
||||
|
||||
mountOptions.propsData = propsData;
|
||||
|
||||
const wrapper = shallowMount(
|
||||
shopPreferenceModal,
|
||||
mountOptions
|
||||
);
|
||||
|
||||
const apiResponses = {};
|
||||
|
||||
settleAllPromises.mockImplementation(() => apiResponses);
|
||||
fetchCmsContentForPage.mockImplementation (() => {});
|
||||
|
||||
return { wrapper };
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,14 +4,18 @@
|
|||
:modalId="ModalName"
|
||||
:footerButtonText="ModalCloseButtonText"
|
||||
@footer-button-event="footerButtonClick">
|
||||
<h5 class="text-center mb-4">{{ModalHeadline}}</h5>
|
||||
<h5 class="text-center mb-4">
|
||||
{{ ModalHeadline }}
|
||||
</h5>
|
||||
<div>
|
||||
<div class="mb-4" v-html="ModalBodyText"></div>
|
||||
<div
|
||||
class="mb-4"
|
||||
v-html="ModalBodyText"></div>
|
||||
<a
|
||||
class="modal-text"
|
||||
v-if="showSteeringLink"
|
||||
v-html="ModalSubBodyText"
|
||||
@click="openSteeringModal">
|
||||
class="modal-text"
|
||||
@click="openSteeringModal"
|
||||
v-html="ModalSubBodyText">
|
||||
</a>
|
||||
</div>
|
||||
</modal>
|
||||
|
|
@ -23,6 +27,9 @@ import { states } from '@/constants/states';
|
|||
|
||||
export default {
|
||||
name: 'content-group-modal',
|
||||
components: {
|
||||
modal
|
||||
},
|
||||
props: {
|
||||
cmsWidgetName: String,
|
||||
showSteeringLink: Boolean
|
||||
|
|
@ -42,8 +49,8 @@ export default {
|
|||
return this.getCmsContent(this.cmsWidgetName, 'BodyText');
|
||||
},
|
||||
ModalSubBodyText() {
|
||||
let header = this.getCmsContent(this.cmsWidgetName, 'BodyText2');
|
||||
return header.replace('{custom:state}', states[this.mainStore.order.customer.address.state])
|
||||
const header = this.getCmsContent(this.cmsWidgetName, 'BodyText2');
|
||||
return header.replace('{custom:state}', states[this.mainStore.order.customer.address.state]);
|
||||
},
|
||||
ModalImage() {
|
||||
return this.getCmsContent(this.cmsWidgetName, 'Image');
|
||||
|
|
@ -63,14 +70,11 @@ export default {
|
|||
this.$refs[this.ModalName].closeModal();
|
||||
this.$emit('openSteering');
|
||||
}
|
||||
},
|
||||
components: {
|
||||
modal
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
<style lang="scss" scoped>
|
||||
.modal {
|
||||
&.modal-component {
|
||||
.modal-dialog {
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
import steeringModal from './steering-modal.vue'
|
||||
|
||||
import { shallowMount } from '@vue/test-utils';
|
||||
import { settleAllPromises } from '@/helpers/layout-helper.js';
|
||||
import { fetchCmsContentForPage, setupModalLinks } from '@/helpers/cms-content-helper';
|
||||
import { fetchCmsContentForPage } from '@/helpers/cms-content-helper';
|
||||
import { getMountOptions } from '@/helpers/unit-test-helper.js';
|
||||
import { useMainStore } from '@/store';
|
||||
import steeringModal from './steering-modal';
|
||||
|
||||
// Mock our module for promises.
|
||||
jest.mock('@/helpers/layout-helper.js', () => ({
|
||||
|
|
@ -17,15 +16,6 @@ jest.mock('@/helpers/cms-content-helper', () => ({
|
|||
setupModalLinks: jest.fn()
|
||||
}));
|
||||
|
||||
describe('steering-modal.vue', () => {
|
||||
test('getStateSpecificText should return true if state matches', () => {
|
||||
const { wrapper } = setupMocks();
|
||||
|
||||
useMainStore().order.customer.address.state = 'OH';
|
||||
expect(wrapper.vm.getStateSpecificText('OH')).toBeTruthy();
|
||||
})
|
||||
});
|
||||
|
||||
function setupMocks() {
|
||||
const mountOptions = getMountOptions({
|
||||
router: {
|
||||
|
|
@ -33,10 +23,8 @@ function setupMocks(){
|
|||
}
|
||||
});
|
||||
|
||||
const wrapper = shallowMount(
|
||||
steeringModal,
|
||||
mountOptions
|
||||
);
|
||||
const wrapper = shallowMount(steeringModal,
|
||||
mountOptions);
|
||||
|
||||
const apiResponses = {};
|
||||
|
||||
|
|
@ -45,3 +33,12 @@ function setupMocks(){
|
|||
|
||||
return { wrapper };
|
||||
}
|
||||
|
||||
describe('steering-modal.vue', () => {
|
||||
test('getStateSpecificText should return true if state matches', () => {
|
||||
const { wrapper } = setupMocks();
|
||||
|
||||
useMainStore().order.customer.address.state = 'OH';
|
||||
expect(wrapper.vm.getStateSpecificText('OH')).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -4,10 +4,16 @@
|
|||
:modalId="ModalName"
|
||||
:footerButtonText="ModalCloseButtonText"
|
||||
@footer-button-event="footerButtonClick">
|
||||
<h5 class="text-center mb-4">{{ModalHeadline}}</h5>
|
||||
<h5 class="text-center mb-4">
|
||||
{{ ModalHeadline }}
|
||||
</h5>
|
||||
<div>
|
||||
<div class="mb-4" v-html="ModalBodyText"></div>
|
||||
<div v-if="ModalSubBodyText" v-html="ModalSubBodyText"></div>
|
||||
<div
|
||||
class="mb-4"
|
||||
v-html="ModalBodyText"></div>
|
||||
<div
|
||||
v-if="ModalSubBodyText"
|
||||
v-html="ModalSubBodyText"></div>
|
||||
</div>
|
||||
</modal>
|
||||
</template>
|
||||
|
|
@ -19,6 +25,9 @@ import { states } from '@/constants/states';
|
|||
|
||||
export default {
|
||||
name: 'content-group-modal',
|
||||
components: {
|
||||
modal
|
||||
},
|
||||
props: {
|
||||
cmsWidgetName: String
|
||||
},
|
||||
|
|
@ -27,8 +36,8 @@ export default {
|
|||
return this.cmsWidgetName;
|
||||
},
|
||||
ModalHeadline() {
|
||||
let header = this.getCmsContent(this.cmsWidgetName, 'HeaderText');
|
||||
return header.replace('{custom:state}', states[this.mainStore.order.customer.address.state])
|
||||
const header = this.getCmsContent(this.cmsWidgetName, 'HeaderText');
|
||||
return header.replace('{custom:state}', states[this.mainStore.order.customer.address.state]);
|
||||
},
|
||||
ModalSubheadertext() {
|
||||
return this.getCmsContent(this.cmsWidgetName, 'SubheaderText');
|
||||
|
|
@ -60,14 +69,11 @@ export default {
|
|||
getStateSpecificText(value) {
|
||||
return this.mainStore.order.customer.address.state?.toLowerCase() == value?.toLowerCase();
|
||||
}
|
||||
},
|
||||
components: {
|
||||
modal
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
<style lang="scss" scoped>
|
||||
.modal {
|
||||
&.modal-component {
|
||||
.modal-dialog {
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
import tpaRecalModal from './tpa-recal-modal.vue'
|
||||
|
||||
import { shallowMount } from '@vue/test-utils';
|
||||
import { settleAllPromises } from '@/helpers/layout-helper.js';
|
||||
import { fetchCmsContentForPage } from '@/helpers/cms-content-helper';
|
||||
import { getMountOptions } from '@/helpers/unit-test-helper.js';
|
||||
import tpaRecalModal from './tpa-recal-modal';
|
||||
|
||||
// Mock our module for promises.
|
||||
jest.mock('@/helpers/layout-helper.js', () => ({
|
||||
|
|
@ -16,24 +15,6 @@ jest.mock('@/helpers/cms-content-helper', () => ({
|
|||
setupModalLinks: jest.fn()
|
||||
}));
|
||||
|
||||
describe('tpa-Recal-Modal.vue', () => {
|
||||
test('should show error if not acknowledged', () => {
|
||||
const { wrapper } = setupMocks();
|
||||
wrapper.vm.acknowledged = false;
|
||||
wrapper.vm.footerButtonClick();
|
||||
|
||||
expect(wrapper.vm.showError).toBeTruthy();
|
||||
})
|
||||
|
||||
test('should not show error if acknowledged', () => {
|
||||
const { wrapper } = setupMocks();
|
||||
wrapper.vm.acknowledged = true;
|
||||
wrapper.vm.footerButtonClick();
|
||||
|
||||
expect(wrapper.vm.showError).toBeFalsy();
|
||||
})
|
||||
});
|
||||
|
||||
function setupMocks() {
|
||||
const mountOptions = getMountOptions({
|
||||
router: {
|
||||
|
|
@ -41,10 +22,8 @@ function setupMocks(){
|
|||
}
|
||||
});
|
||||
|
||||
const wrapper = shallowMount(
|
||||
tpaRecalModal,
|
||||
mountOptions
|
||||
);
|
||||
const wrapper = shallowMount(tpaRecalModal,
|
||||
mountOptions);
|
||||
|
||||
const apiResponses = {};
|
||||
|
||||
|
|
@ -53,3 +32,21 @@ function setupMocks(){
|
|||
|
||||
return { wrapper };
|
||||
}
|
||||
|
||||
describe('tpa-Recal-Modal.vue', () => {
|
||||
test('should show error if not acknowledged', () => {
|
||||
const { wrapper } = setupMocks();
|
||||
wrapper.vm.acknowledged = false;
|
||||
wrapper.vm.footerButtonClick();
|
||||
|
||||
expect(wrapper.vm.showError).toBeTruthy();
|
||||
});
|
||||
|
||||
test('should not show error if acknowledged', () => {
|
||||
const { wrapper } = setupMocks();
|
||||
wrapper.vm.acknowledged = true;
|
||||
wrapper.vm.footerButtonClick();
|
||||
|
||||
expect(wrapper.vm.showError).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -3,14 +3,22 @@
|
|||
:ref="ModalName"
|
||||
:modalId="ModalName"
|
||||
:footerButtonText="ModalCloseButtonText"
|
||||
@footer-button-event="footerButtonClick"
|
||||
:isButtonDisabled="isButtonDisabled">
|
||||
:isButtonDisabled="isButtonDisabled"
|
||||
@footer-button-event="footerButtonClick">
|
||||
<div class="form-test-invalid">
|
||||
<h5 class="text-center mb-4">{{ModalHeadline}}</h5>
|
||||
<h5 class="text-center mb-4">
|
||||
{{ ModalHeadline }}
|
||||
</h5>
|
||||
<div>
|
||||
<div class="mb-4" v-html="ModalBodyText"></div>
|
||||
<tpaRecalToggle class="mb-5" cmsWidgetName="TPARecalModalToggle"/>
|
||||
<div
|
||||
class="mb-4"
|
||||
v-html="ModalBodyText"></div>
|
||||
<tpaRecalToggle
|
||||
class="mb-5"
|
||||
cmsWidgetName="TPARecalModalToggle" />
|
||||
<checkBox
|
||||
ref="tpaAcknowledgement"
|
||||
v-model="acknowledged"
|
||||
class="mb-2"
|
||||
:class="showError && ' has-error'"
|
||||
:validationRules="rules.optionRequired"
|
||||
|
|
@ -19,11 +27,10 @@
|
|||
:tabIndex="0"
|
||||
:checkboxLabel="ModalSubBodyText"
|
||||
:screenReaderOnlyText="ModalSubBodyText"
|
||||
isRequired
|
||||
ref="tpaAcknowledgement"
|
||||
v-model="acknowledged"
|
||||
/>
|
||||
<div v-if="showError" class="row form-test-error mt-1">
|
||||
isRequired />
|
||||
<div
|
||||
v-if="showError"
|
||||
class="row form-test-error mt-1">
|
||||
<p>{{ ackError }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -33,16 +40,22 @@
|
|||
|
||||
<script>
|
||||
import modal from '@/digital-components/modal/modal';
|
||||
import tpaRecalToggle from '@/layouts/provider-preference/tpa-recal-modal/tpa-recal-toggle/tpa-recal-toggle.vue'
|
||||
import checkBox from '@/ux-components/checkbox/checkbox.vue'
|
||||
import tpaRecalToggle from '@/layouts/provider-preference/tpa-recal-modal/tpa-recal-toggle/tpa-recal-toggle';
|
||||
import checkBox from '@/ux-components/checkbox/checkbox';
|
||||
import globalRules from '@/constants/global-rules';
|
||||
|
||||
export default {
|
||||
name: 'content-group-modal',
|
||||
components: {
|
||||
modal,
|
||||
tpaRecalToggle,
|
||||
checkBox
|
||||
},
|
||||
props: {
|
||||
cmsWidgetName: String,
|
||||
ackError: String
|
||||
},
|
||||
emits: ['buttonClick'],
|
||||
data() {
|
||||
return {
|
||||
acknowledged: false,
|
||||
|
|
@ -52,7 +65,6 @@ export default {
|
|||
}
|
||||
};
|
||||
},
|
||||
emits: ['buttonClick'],
|
||||
computed: {
|
||||
ModalName() {
|
||||
return this.cmsWidgetName;
|
||||
|
|
@ -70,7 +82,12 @@ export default {
|
|||
return this.getCmsContent(this.cmsWidgetName, 'FooterText');
|
||||
},
|
||||
isButtonDisabled() {
|
||||
return !this.acknowledged
|
||||
return !this.acknowledged;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
acknowledged() {
|
||||
this.showError = false;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
|
@ -80,8 +97,7 @@ export default {
|
|||
|
||||
footerButtonClick() {
|
||||
// check if acked, if not show error
|
||||
if (this.acknowledged)
|
||||
{
|
||||
if (this.acknowledged) {
|
||||
this.$refs[this.ModalName]?.closeModal();
|
||||
this.$emit('buttonClick');
|
||||
} else {
|
||||
|
|
@ -89,21 +105,11 @@ export default {
|
|||
this.showError = true;
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
acknowledged() {
|
||||
this.showError = false;
|
||||
}
|
||||
},
|
||||
components: {
|
||||
modal,
|
||||
tpaRecalToggle,
|
||||
checkBox
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
<style lang="scss" scoped>
|
||||
.modal {
|
||||
&.modal-component {
|
||||
.modal-dialog {
|
||||
|
|
|
|||
|
|
@ -1,11 +1,10 @@
|
|||
/* eslint-env jest */
|
||||
import { render } from '@testing-library/vue';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import '@testing-library/jest-dom';
|
||||
import { issPageValues } from '@/router/router-constants/issPage-values';
|
||||
import { queryStrings } from '@/constants/query-strings';
|
||||
import { GaActions } from '@/constants/analytics';
|
||||
import tpaRecalToggle from './tpa-recal-toggle.vue';
|
||||
import tpaRecalToggle from './tpa-recal-toggle';
|
||||
|
||||
const mockText = Object.freeze({
|
||||
HEADER: 'Mock Header',
|
||||
|
|
@ -72,7 +71,7 @@ describe('more details section', () => {
|
|||
test('should toggle when arrow clicked', async () => {
|
||||
const user = userEvent.setup();
|
||||
const { container } = render(tpaRecalToggle, mountOptions);
|
||||
const toggleLink = container.querySelector('#moreDetails');;
|
||||
const toggleLink = container.querySelector('#moreDetails');
|
||||
|
||||
await user.click(toggleLink);
|
||||
let moreDetailsSection = container.querySelector('#tpa-recal-detail-wrapper');
|
||||
|
|
|
|||
|
|
@ -3,41 +3,37 @@
|
|||
<div
|
||||
class="tpa-toggle"
|
||||
:class="[isDetailVisible ? 'active' : '']"
|
||||
@click="handleClickToggle"
|
||||
>
|
||||
@click="handleClickToggle">
|
||||
<textLink
|
||||
id="moreDetails"
|
||||
linkType="text"
|
||||
href="#!"
|
||||
:text="textForToggle"
|
||||
id="moreDetails"
|
||||
/>
|
||||
:text="textForToggle" />
|
||||
</div>
|
||||
<Transition>
|
||||
<div
|
||||
v-show="isDetailVisible"
|
||||
id="tpa-recal-detail-wrapper"
|
||||
class="mt-2"
|
||||
>
|
||||
class="mt-2">
|
||||
<div
|
||||
v-html="detailContent"
|
||||
id="tpa-recal-detail-content"
|
||||
class="mb-2"
|
||||
/>
|
||||
v-html="detailContent" />
|
||||
</div>
|
||||
</Transition>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import textLink from '@/ux-components/text-link/text-link.vue';
|
||||
import textLink from '@/ux-components/text-link/text-link';
|
||||
|
||||
export default {
|
||||
name: 'tpa-recal-toggle',
|
||||
props: {
|
||||
cmsWidgetName: String
|
||||
},
|
||||
components: {
|
||||
textLink
|
||||
},
|
||||
props: {
|
||||
cmsWidgetName: String
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isDetailVisible: false
|
||||
|
|
@ -58,7 +54,7 @@ export default {
|
|||
}
|
||||
};
|
||||
</script>
|
||||
<style lang="scss">
|
||||
<style lang="scss" scoped>
|
||||
.tpa-recal-toggle {
|
||||
.tpa-toggle {
|
||||
&::after {
|
||||
|
|
|
|||
|
|
@ -1,17 +1,20 @@
|
|||
<template>
|
||||
<Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm" v-slot="{ meta }" >
|
||||
<Form
|
||||
ref="theForm"
|
||||
v-slot="{ meta }"
|
||||
@submit="onSubmit"
|
||||
@invalid-submit="onInvalidSubmit">
|
||||
<div class="page-container-grouped-styles">
|
||||
<div class="fade-on-route-transition position-relative">
|
||||
<siteHeader cmsWidgetName="SiteHeaderWidget" />
|
||||
<div class="container-fluid pb-2 review">
|
||||
<p>Placeholder for review page</p>
|
||||
<siteFooter
|
||||
cmsWidgetName="SiteFooterWidget"
|
||||
ref="siteFooter"
|
||||
cmsWidgetName="SiteFooterWidget"
|
||||
:isForwardActionDisabled="!meta.valid"
|
||||
@ForwardClicked="navigateForward"
|
||||
@back-clicked="backButtonAction"
|
||||
/>
|
||||
@back-clicked="backButtonAction" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -27,15 +30,16 @@ import { settleAllPromises } from '@/helpers/layout-helper';
|
|||
import { Form } from 'vee-validate';
|
||||
import BaseFormMixin from '@/mixins/base-form-mixin.js';
|
||||
import { useMainStore } from '@/store';
|
||||
|
||||
export default {
|
||||
name: 'review-page',
|
||||
components: {
|
||||
siteHeader,
|
||||
siteFooter,
|
||||
// eslint-disable-next-line vue/no-reserved-component-names
|
||||
Form
|
||||
},
|
||||
mixins: [BaseFormMixin],
|
||||
data() {
|
||||
},
|
||||
setup() {
|
||||
const mainStore = useMainStore();
|
||||
return { mainStore };
|
||||
},
|
||||
async beforeRouteEnter(to, from, next) {
|
||||
// Call APIs
|
||||
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
|
||||
|
|
@ -46,33 +50,31 @@ export default {
|
|||
promise: cmsContentPromise
|
||||
}];
|
||||
// use resultMap to populate layout content.
|
||||
let resultMap = await settleAllPromises(promiseResultMap);
|
||||
const resultMap = await settleAllPromises(promiseResultMap);
|
||||
next((vm) => {
|
||||
vm.setCmsContent(resultMap.cmsContent);
|
||||
});
|
||||
},
|
||||
methods:
|
||||
{
|
||||
setup() {
|
||||
const mainStore = useMainStore();
|
||||
return { mainStore };
|
||||
},
|
||||
data() {
|
||||
},
|
||||
methods: {
|
||||
backButtonAction() {
|
||||
this.$router.navigate(this.navigationScenarios.CLICKED_BACK, this.$route);
|
||||
},
|
||||
forwardButtonAction() {
|
||||
},
|
||||
navigateForward() {
|
||||
this.$router.navigate(
|
||||
this.navigationScenarios.CLICKED_FORWARD,
|
||||
this.$route
|
||||
);
|
||||
}
|
||||
},
|
||||
components: {
|
||||
siteHeader,
|
||||
siteFooter,
|
||||
Form
|
||||
this.$router.navigate(this.navigationScenarios.CLICKED_FORWARD,
|
||||
this.$route);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style lang="scss">
|
||||
<style lang="scss" scoped>
|
||||
.review p{
|
||||
margin-bottom:0.75rem;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,18 +1,21 @@
|
|||
<template>
|
||||
<Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm" v-slot="{ meta }" >
|
||||
<Form
|
||||
ref="theForm"
|
||||
v-slot="{ meta }"
|
||||
@submit="onSubmit"
|
||||
@invalid-submit="onInvalidSubmit">
|
||||
<div class="page-container-grouped-styles">
|
||||
<div class="fade-on-route-transition position-relative">
|
||||
<siteHeader cmsWidgetName="SiteHeaderWidget" />
|
||||
<div class="container-fluid pb-2">
|
||||
<p>Placeholder for schedule page</p>
|
||||
<siteFooter
|
||||
ref="siteFooter"
|
||||
class="mt-5"
|
||||
cmsWidgetName="SiteFooterWidget"
|
||||
ref="siteFooter"
|
||||
:isForwardActionDisabled="!meta.valid"
|
||||
@ForwardClicked="forwardButtonAction"
|
||||
@back-clicked="backButtonAction"
|
||||
/>
|
||||
@back-clicked="backButtonAction" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -32,16 +35,14 @@ import { useMainStore } from '@/store';
|
|||
|
||||
export default {
|
||||
name: 'schedule-page',
|
||||
components: {
|
||||
siteHeader,
|
||||
siteFooter,
|
||||
// eslint-disable-next-line vue/no-reserved-component-names
|
||||
Form
|
||||
},
|
||||
mixins: [BaseFormMixin],
|
||||
data() {
|
||||
|
||||
},
|
||||
setup() {
|
||||
const mainStore = useMainStore();
|
||||
return { mainStore };
|
||||
},
|
||||
async beforeRouteEnter(to, from, next)
|
||||
{
|
||||
async beforeRouteEnter(to, from, next) {
|
||||
// Call APIs
|
||||
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
|
||||
|
||||
|
|
@ -53,11 +54,18 @@ export default {
|
|||
}];
|
||||
|
||||
// use resultMap to populate layout content.
|
||||
let resultMap = await settleAllPromises(promiseResultMap);
|
||||
const resultMap = await settleAllPromises(promiseResultMap);
|
||||
|
||||
next((vm) => {
|
||||
vm.setCmsContent(resultMap.cmsContent);
|
||||
});
|
||||
},
|
||||
setup() {
|
||||
const mainStore = useMainStore();
|
||||
return { mainStore };
|
||||
},
|
||||
data() {
|
||||
|
||||
},
|
||||
methods:
|
||||
{
|
||||
|
|
@ -72,13 +80,6 @@ export default {
|
|||
|
||||
navigateForward() {
|
||||
}
|
||||
},
|
||||
components: {
|
||||
siteHeader,
|
||||
siteFooter,
|
||||
Form
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style lang="scss">
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,16 +1,24 @@
|
|||
import { shallowMount } from '@vue/test-utils';
|
||||
import { getMountOptions } from '@/helpers/unit-test-helper.js';
|
||||
import serviceLocation from '@/layouts/service-location/service-location.vue';
|
||||
import { getServiceabilityDetails, getZipCodeData } from '@/helpers/service-location-helper';
|
||||
import serviceLocation from '@/layouts/service-location/service-location';
|
||||
|
||||
// Define Mocks
|
||||
jest.mock('@/helpers/cms-content-helper', () => ({
|
||||
fetchCmsContentForPage: jest.fn(() => {
|
||||
return Promise.resolve('content');
|
||||
})
|
||||
fetchCmsContentForPage: jest.fn(() => Promise.resolve('content'))
|
||||
}));
|
||||
|
||||
const mockGetServiceabilityDetails = (mockServiceZipCode) => {
|
||||
function setupMocks() {
|
||||
const wrapper = shallowMount(serviceLocation,
|
||||
getMountOptions({
|
||||
router: {
|
||||
navigate: jest.fn()
|
||||
}
|
||||
}));
|
||||
|
||||
return { wrapper };
|
||||
}
|
||||
|
||||
const mockGetServiceabilityDetails = () => {
|
||||
const serviceabilityDetails = {
|
||||
isGlassServiceableInshop: true,
|
||||
isRecalibrationServiceableInshop: true,
|
||||
|
|
@ -21,18 +29,15 @@ const mockGetServiceabilityDetails = (mockServiceZipCode) => {
|
|||
return Promise.resolve(serviceabilityDetails);
|
||||
};
|
||||
|
||||
jest.mock(
|
||||
'@/helpers/service-location-helper',
|
||||
jest.mock('@/helpers/service-location-helper',
|
||||
() => ({
|
||||
getServiceabilityDetails: jest.fn((mockServiceZipCode) => {
|
||||
return mockGetServiceabilityDetails(mockServiceZipCode);
|
||||
})
|
||||
})
|
||||
);
|
||||
getServiceabilityDetails: jest.fn((mockServiceZipCode) => mockGetServiceabilityDetails(mockServiceZipCode))
|
||||
}));
|
||||
|
||||
const mockMixin = {
|
||||
methods: {
|
||||
getCmsContent: jest.fn((widgetName, cmsFieldName) => {
|
||||
// linkWidgetName is not defined. This whole spec file needs review.
|
||||
if (widgetName === linkWidgetName) {
|
||||
return mockLinkCmsContent[cmsFieldName];
|
||||
}
|
||||
|
|
@ -130,7 +135,7 @@ describe('updating service zip', () => {
|
|||
|
||||
const newServiceZipCodeQuestion = {
|
||||
zipCode: '45433',
|
||||
state: 'OH',
|
||||
state: 'OH'
|
||||
};
|
||||
|
||||
// Act
|
||||
|
|
@ -140,16 +145,3 @@ describe('updating service zip', () => {
|
|||
expect(wrapper.vm.zipContainsMilitaryBase).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
function setupMocks() {
|
||||
const wrapper = shallowMount(
|
||||
serviceLocation,
|
||||
getMountOptions({
|
||||
router: {
|
||||
navigate: jest.fn()
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
return { wrapper };
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,44 +1,50 @@
|
|||
<template>
|
||||
<Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm" v-slot="{ meta }" >
|
||||
<Form
|
||||
ref="theForm"
|
||||
v-slot="{ meta }"
|
||||
@submit="onSubmit"
|
||||
@invalid-submit="onInvalidSubmit">
|
||||
<div class="page-container-grouped-styles">
|
||||
<div class="fade-on-route-transition position-relative">
|
||||
<siteHeader cmsWidgetName="SiteHeaderWidget" />
|
||||
<siteSubHeader cmsWidgetName="SiteSubHeaderWidget" id="sub-header" class="mt-5" />
|
||||
<siteSubHeader
|
||||
id="sub-header"
|
||||
cmsWidgetName="SiteSubHeaderWidget"
|
||||
class="mt-5" />
|
||||
<div class="select-car">
|
||||
<div class="container-fluid pb-2">
|
||||
<div class="row px-3">
|
||||
<div class="col">
|
||||
<div class="select-car-form rounded">
|
||||
<serviceZipModalQuestion
|
||||
v-model="serviceZipCodeQuestion"
|
||||
ref="serviceZipCodeQuestion"
|
||||
v-model="serviceZipCodeQuestion"
|
||||
modalWidgetName="ServiceZipModalWidget"
|
||||
@updated-serviceability="setServiceabilityDetails"
|
||||
@updated-contains-military-base="setContainsMilitaryBase"
|
||||
modalWidgetName="ServiceZipModalWidget" />
|
||||
@updated-contains-military-base="setContainsMilitaryBase" />
|
||||
<alert
|
||||
v-if="displayMilitaryZipAlert"
|
||||
ref="alertMilitaryBaseZip"
|
||||
class="my-5"
|
||||
cmsWidgetName="AlertMilitaryBaseZipWidget"
|
||||
v-if="displayMilitaryZipAlert"
|
||||
alertClass="alert-warning" />
|
||||
<buttonQuestion
|
||||
v-model="selectedAppointmentType"
|
||||
cmsWidgetName="ServiceTypeQuestionWidget"
|
||||
:questionText="questionText"
|
||||
:answers="answersFromCms"
|
||||
buttonTypeString="listCard"
|
||||
isRequired
|
||||
v-model="selectedAppointmentType"
|
||||
validationRules="selection-required"
|
||||
class="service-location-button-question mb-1" />
|
||||
<div class="select-car">
|
||||
<siteFooter
|
||||
ref="siteFooter"
|
||||
class="mt-5"
|
||||
cmsWidgetName="SiteFooterWidget"
|
||||
:isForwardActionDisabled="!meta.valid"
|
||||
@backClicked="backButtonAction"
|
||||
@forwardClicked="forwardButtonAction"
|
||||
ref="siteFooter"
|
||||
/>
|
||||
@forwardClicked="forwardButtonAction" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -62,17 +68,26 @@ import { getServiceabilityDetails, getZipCodeData } from '@/helpers/service-loca
|
|||
// Import Component
|
||||
import alert from '@/ux-components/alert/alert';
|
||||
import baseFormMixin from '@/mixins/base-form-mixin';
|
||||
import baseMixin from '@/mixins/base-mixin';
|
||||
import { Form, defineRule } from 'vee-validate';
|
||||
import siteFooter from '@/iss-components/site-footer/site-footer.vue';
|
||||
import siteHeader from '@/iss-components/site-header/site-header.vue';
|
||||
import siteSubHeader from '@/iss-components/site-sub-header/site-sub-header.vue';
|
||||
import serviceZipModalQuestion from '@/layouts/service-location/service-zip-modal-question/service-zip-modal-question.vue';
|
||||
import siteFooter from '@/iss-components/site-footer/site-footer';
|
||||
import siteHeader from '@/iss-components/site-header/site-header';
|
||||
import siteSubHeader from '@/iss-components/site-sub-header/site-sub-header';
|
||||
import serviceZipModalQuestion from '@/layouts/service-location/service-zip-modal-question/service-zip-modal-question';
|
||||
|
||||
// DEFINE VALIDATION RULES
|
||||
defineRule('selection-required', required(errorMessages.OPTION_REQUIRED));
|
||||
export default {
|
||||
name: 'service-location',
|
||||
components: {
|
||||
siteFooter,
|
||||
siteHeader,
|
||||
siteSubHeader,
|
||||
buttonQuestion,
|
||||
// eslint-disable-next-line vue/no-reserved-component-names
|
||||
Form,
|
||||
serviceZipModalQuestion,
|
||||
alert
|
||||
},
|
||||
mixins: [baseFormMixin],
|
||||
async beforeRouteEnter(to, from, next) {
|
||||
// Call APIs
|
||||
|
|
@ -103,10 +118,8 @@ export default {
|
|||
|
||||
next((vm) => {
|
||||
vm.setCmsContent(resultMap.cmsContent);
|
||||
vm.setData(
|
||||
resultMap.zipCodeData,
|
||||
resultMap.serviceabilityDetails
|
||||
)
|
||||
vm.setData(resultMap.zipCodeData,
|
||||
resultMap.serviceabilityDetails);
|
||||
});
|
||||
},
|
||||
setup() {
|
||||
|
|
@ -132,25 +145,25 @@ export default {
|
|||
return this.getCmsContent('ServiceTypeQuestionWidget', 'Answers');
|
||||
},
|
||||
serviceZipCodeQuestion: {
|
||||
get: function() {
|
||||
get() {
|
||||
return {
|
||||
zipCode: this.zipCode,
|
||||
state: this.state
|
||||
};
|
||||
},
|
||||
set: function (newValue) {
|
||||
set(newValue) {
|
||||
this.zipCode = newValue.zipCode;
|
||||
this.state = newValue.state;
|
||||
|
||||
// TODO: review - this seems like it should be awaited.
|
||||
this.$nextTick();
|
||||
}
|
||||
},
|
||||
isServiceableMobile() {
|
||||
if (this.isRecalibrationServiceableMobile !== null) {
|
||||
return this.isGlassServiceableMobile && this.isRecalibrationServiceableMobile;
|
||||
} else {
|
||||
return this.isGlassServiceableMobile;
|
||||
}
|
||||
return this.isGlassServiceableMobile;
|
||||
},
|
||||
displayMilitaryZipAlert() {
|
||||
return this.zipContainsMilitaryBase && this.isServiceableMobile;
|
||||
|
|
@ -188,26 +201,17 @@ export default {
|
|||
},
|
||||
setServiceabilityDetails(serviceabilityDetails) {
|
||||
this.isGlassServiceableInshop = serviceabilityDetails.isGlassServiceableInshop;
|
||||
this.isRecalibrationServiceableInshop =
|
||||
serviceabilityDetails.isRecalibrationServiceableInshop;
|
||||
this.isRecalibrationServiceableInshop
|
||||
= serviceabilityDetails.isRecalibrationServiceableInshop;
|
||||
this.isGlassServiceableMobile = serviceabilityDetails.isGlassServiceableMobile;
|
||||
this.isRecalibrationServiceableMobile =
|
||||
serviceabilityDetails.isRecalibrationServiceableMobile;
|
||||
this.isRecalibrationServiceableMobile
|
||||
= serviceabilityDetails.isRecalibrationServiceableMobile;
|
||||
}
|
||||
},
|
||||
components: {
|
||||
siteFooter,
|
||||
siteHeader,
|
||||
siteSubHeader,
|
||||
buttonQuestion,
|
||||
Form,
|
||||
serviceZipModalQuestion,
|
||||
alert
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
<style lang="scss" scoped>
|
||||
|
||||
.page-container-grouped-styles {
|
||||
overflow: auto;
|
||||
|
|
|
|||
|
|
@ -1,13 +1,11 @@
|
|||
import { mount, shallowMount } from '@vue/test-utils';
|
||||
import serviceZipModalQuestion from './service-zip-modal-question';
|
||||
import { mount } from '@vue/test-utils';
|
||||
import crypto from 'crypto';
|
||||
import serviceZipModalQuestion from './service-zip-modal-question';
|
||||
|
||||
global.crypto = crypto;
|
||||
|
||||
jest.mock('@/digital-components/textbox-question/textbox-question', () => ({
|
||||
getCmsContent: jest.fn((widgetName, cmsFieldName) => {
|
||||
return widgetName[cmsFieldName];
|
||||
})
|
||||
getCmsContent: jest.fn((widgetName, cmsFieldName) => widgetName[cmsFieldName])
|
||||
}));
|
||||
|
||||
jest.mock('@/digital-components/modal/modal', () => ({
|
||||
|
|
@ -17,7 +15,7 @@ jest.mock('@/digital-components/modal/modal', () => ({
|
|||
}
|
||||
}));
|
||||
|
||||
const mockGetServiceabilityDetails = (mockServiceZipCode) => {
|
||||
const mockGetServiceabilityDetails = () => {
|
||||
const serviceabilityDetails = {
|
||||
isGlassServiceableInshop: true,
|
||||
isRecalibrationServiceableInshop: true,
|
||||
|
|
@ -53,19 +51,13 @@ const mockGetZipCodeData = (mockServiceZipCode) => {
|
|||
state: null,
|
||||
zipCodeCtu: null
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
jest.mock(
|
||||
'@/helpers/service-location-helper',
|
||||
jest.mock('@/helpers/service-location-helper',
|
||||
() => ({
|
||||
getServiceabilityDetails: jest.fn((mockServiceZipCode) => {
|
||||
return mockGetServiceabilityDetails(mockServiceZipCode);
|
||||
}),
|
||||
getZipCodeData: jest.fn((mockServiceZipCode) => {
|
||||
return mockGetZipCodeData(mockServiceZipCode);
|
||||
})
|
||||
})
|
||||
);
|
||||
getServiceabilityDetails: jest.fn((mockServiceZipCode) => mockGetServiceabilityDetails(mockServiceZipCode)),
|
||||
getZipCodeData: jest.fn((mockServiceZipCode) => mockGetZipCodeData(mockServiceZipCode))
|
||||
}));
|
||||
|
||||
const linkWidgetName = 'linkWidgetName';
|
||||
const modalWidgetName = 'modalWidgetName';
|
||||
|
|
@ -91,12 +83,12 @@ const mockMixin = {
|
|||
return null;
|
||||
})
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
describe('service-zip-modal-question.vue', () => {
|
||||
it('Initial state on load with existing location info', async () => {
|
||||
// Arrange
|
||||
let serviceZipCodeQuestion = {
|
||||
const serviceZipCodeQuestion = {
|
||||
state: 'OH',
|
||||
zipCode: '43235'
|
||||
};
|
||||
|
|
@ -105,19 +97,19 @@ describe('service-zip-modal-question.vue', () => {
|
|||
mixins: [mockMixin],
|
||||
props: {
|
||||
modelValue: serviceZipCodeQuestion,
|
||||
linkWidgetName: linkWidgetName,
|
||||
modalWidgetName: modalWidgetName
|
||||
linkWidgetName,
|
||||
modalWidgetName
|
||||
},
|
||||
attachTo: document.body
|
||||
});
|
||||
|
||||
// Assert
|
||||
expect(wrapper.html()).not.toEqual(expect.stringContaining(mockLinkCmsContent['BodyText']));
|
||||
expect(wrapper.html()).not.toEqual(expect.stringContaining(mockLinkCmsContent.BodyText));
|
||||
});
|
||||
|
||||
it('Should emit update:modelValue on setZipCode for a valid, serviceable zip', async () => {
|
||||
// Arrange
|
||||
let serviceZipCodeQuestion = {
|
||||
const serviceZipCodeQuestion = {
|
||||
state: 'IL',
|
||||
zipCode: '61606'
|
||||
};
|
||||
|
|
@ -129,7 +121,7 @@ describe('service-zip-modal-question.vue', () => {
|
|||
props: {
|
||||
modelValue: serviceZipCodeQuestion,
|
||||
mobileFeePart: {},
|
||||
modalWidgetName: modalWidgetName
|
||||
modalWidgetName
|
||||
},
|
||||
attachTo: document.body
|
||||
});
|
||||
|
|
@ -139,7 +131,7 @@ describe('service-zip-modal-question.vue', () => {
|
|||
|
||||
await wrapper.vm.setZipCode();
|
||||
|
||||
let expectedEmit = [[{ state: 'OH', zipCode: '43235' }]];
|
||||
const expectedEmit = [[{ state: 'OH', zipCode: '43235' }]];
|
||||
|
||||
// Assert
|
||||
expect(wrapper.emitted('update:modelValue')).toEqual(expectedEmit);
|
||||
|
|
@ -147,7 +139,7 @@ describe('service-zip-modal-question.vue', () => {
|
|||
|
||||
it('Should not emit update:modelValue on setZipCode for an invalid zip', async () => {
|
||||
// Arrange
|
||||
let serviceZipCodeQuestion = {
|
||||
const serviceZipCodeQuestion = {
|
||||
state: 'IL',
|
||||
zipCode: '61606'
|
||||
};
|
||||
|
|
@ -158,7 +150,7 @@ describe('service-zip-modal-question.vue', () => {
|
|||
mixins: [mockMixin],
|
||||
props: {
|
||||
modelValue: serviceZipCodeQuestion,
|
||||
modalWidgetName: modalWidgetName
|
||||
modalWidgetName
|
||||
},
|
||||
attachTo: document.body
|
||||
});
|
||||
|
|
@ -173,7 +165,7 @@ describe('service-zip-modal-question.vue', () => {
|
|||
|
||||
it('Should display invalid zip alerts for invalid ip inputs', async () => {
|
||||
// Arrange
|
||||
let serviceZipCodeQuestion = {
|
||||
const serviceZipCodeQuestion = {
|
||||
state: 'IL',
|
||||
zipCode: '61606'
|
||||
};
|
||||
|
|
@ -184,7 +176,7 @@ describe('service-zip-modal-question.vue', () => {
|
|||
mixins: [mockMixin],
|
||||
props: {
|
||||
modelValue: serviceZipCodeQuestion,
|
||||
modalWidgetName: modalWidgetName
|
||||
modalWidgetName
|
||||
},
|
||||
attachTo: document.body
|
||||
});
|
||||
|
|
@ -199,7 +191,7 @@ describe('service-zip-modal-question.vue', () => {
|
|||
|
||||
it('Should reset all alerts on onModalClosed', async () => {
|
||||
// Arrange
|
||||
let serviceZipCodeQuestion = {
|
||||
const serviceZipCodeQuestion = {
|
||||
state: 'IL',
|
||||
zipCode: '61606'
|
||||
};
|
||||
|
|
@ -210,7 +202,7 @@ describe('service-zip-modal-question.vue', () => {
|
|||
mixins: [mockMixin],
|
||||
props: {
|
||||
modelValue: serviceZipCodeQuestion,
|
||||
modalWidgetName: modalWidgetName
|
||||
modalWidgetName
|
||||
},
|
||||
attachTo: document.body
|
||||
});
|
||||
|
|
@ -226,7 +218,7 @@ describe('service-zip-modal-question.vue', () => {
|
|||
|
||||
it('Should prepopulate the zip on onModalOpened', async () => {
|
||||
// Arrange
|
||||
let serviceZipCodeQuestion = {
|
||||
const serviceZipCodeQuestion = {
|
||||
state: 'IL',
|
||||
zipCode: '61606'
|
||||
};
|
||||
|
|
@ -237,7 +229,7 @@ describe('service-zip-modal-question.vue', () => {
|
|||
mixins: [mockMixin],
|
||||
props: {
|
||||
modelValue: serviceZipCodeQuestion,
|
||||
modalWidgetName: modalWidgetName
|
||||
modalWidgetName
|
||||
},
|
||||
attachTo: document.body
|
||||
});
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@
|
|||
linkType="text"
|
||||
:text="serviceZipLinkText"
|
||||
href="#!"
|
||||
@click-event="openModal"
|
||||
aria-label="Modal window" />
|
||||
aria-label="Modal window"
|
||||
@click-event="openModal" />
|
||||
</div>
|
||||
</div>
|
||||
<modal
|
||||
|
|
@ -19,37 +19,35 @@
|
|||
@footer-button-event="setZipCode">
|
||||
<serviceZipQuestion
|
||||
ref="serviceZipCodeQuestion"
|
||||
customInputId="serviceZipCode"
|
||||
v-model="internalModel.zipCode"
|
||||
v-on="{ 'textboxQuestionEvent.inputIdAssigned': onInputIdAssigned }"
|
||||
:cmsWidgetName="textboxQuestionWidgetName" />
|
||||
customInputId="serviceZipCode"
|
||||
:cmsWidgetName="textboxQuestionWidgetName"
|
||||
v-on="{ 'textboxQuestionEvent.inputIdAssigned': onInputIdAssigned }" />
|
||||
<alert
|
||||
ref="alertInvalidZip"
|
||||
v-if="displayInvalidZipAlert"
|
||||
ref="alertInvalidZip"
|
||||
class="my-4"
|
||||
:cmsWidgetName="alertInvalidZipWidgetName"
|
||||
alertClass="alert-danger"
|
||||
v-bind:isDismissible="false" />
|
||||
:isDismissible="false" />
|
||||
</modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import textLink from '@/ux-components/text-link/text-link';
|
||||
import serviceZipQuestion from '@/layouts/service-location/service-zip-modal-question/service-zip-question/service-zip-question';
|
||||
import modal from '@/digital-components/modal/modal.vue'
|
||||
import modal from '@/digital-components/modal/modal';
|
||||
import alert from '@/ux-components/alert/alert';
|
||||
|
||||
import { getServiceabilityDetails, getZipCodeData } from '@/helpers/service-location-helper';
|
||||
|
||||
export default {
|
||||
name: 'service-zip-modal-question',
|
||||
emits: ['update:modelValue', 'updated-serviceability', 'updated-contains-military-base'],
|
||||
data() {
|
||||
return {
|
||||
internalModel: this.copyModel(this.modelValue),
|
||||
serviceZipCodeTextInputId: '',
|
||||
displayInvalidZipAlert: false
|
||||
};
|
||||
components: {
|
||||
textLink,
|
||||
modal,
|
||||
serviceZipQuestion,
|
||||
alert
|
||||
},
|
||||
props: {
|
||||
modelValue: {
|
||||
|
|
@ -61,6 +59,7 @@ export default {
|
|||
},
|
||||
modalWidgetName: String
|
||||
},
|
||||
emits: ['update:modelValue', 'updated-serviceability', 'updated-contains-military-base'],
|
||||
setup() {
|
||||
const textboxQuestionWidgetName = 'ServiceZipQuestionWidget';
|
||||
const alertInvalidZipWidgetName = 'AlertInvalidZipWidget';
|
||||
|
|
@ -69,11 +68,19 @@ export default {
|
|||
alertInvalidZipWidgetName
|
||||
};
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
internalModel: this.copyModel(this.modelValue),
|
||||
serviceZipCodeTextInputId: '',
|
||||
displayInvalidZipAlert: false
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
serviceZipLinkText() {
|
||||
if (this.modelValue.zipCode && this.modelValue.zipCode.length > 0) {
|
||||
return this.modelValue.state + ', ' + this.modelValue.zipCode;
|
||||
return `${this.modelValue.state}, ${this.modelValue.zipCode}`;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
modalHeaderText() {
|
||||
return this.getCmsContent(this.textboxQuestionWidgetName, 'QuestionText');
|
||||
|
|
@ -85,6 +92,16 @@ export default {
|
|||
return this.modalWidgetName;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
modelValue(newValue) {
|
||||
this.internalModel = this.copyModel(newValue);
|
||||
},
|
||||
'internalModel.zipCode': {
|
||||
handler() {
|
||||
this.resetsOnZipInput();
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
resetAlerts() {
|
||||
this.displayInvalidZipAlert = false;
|
||||
|
|
@ -152,22 +169,6 @@ export default {
|
|||
}
|
||||
},
|
||||
getZipCodeData
|
||||
},
|
||||
watch: {
|
||||
modelValue(newValue) {
|
||||
this.internalModel = this.copyModel(newValue);
|
||||
},
|
||||
'internalModel.zipCode': {
|
||||
handler() {
|
||||
this.resetsOnZipInput();
|
||||
}
|
||||
}
|
||||
},
|
||||
components: {
|
||||
textLink,
|
||||
modal,
|
||||
serviceZipQuestion,
|
||||
alert
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@ describe('service-zip-question.vue', () => {
|
|||
});
|
||||
|
||||
// Act
|
||||
const modelValueText = wrapper.vm.value;
|
||||
wrapper.vm.value = 'test also';
|
||||
|
||||
// Assert
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
<template>
|
||||
<textboxQuestion
|
||||
ref="zipInputTextQuestion"
|
||||
:cmsWidgetName="cmsWidgetName"
|
||||
v-model="value"
|
||||
:cmsWidgetName="cmsWidgetName"
|
||||
inputId="serviceZipCode"
|
||||
questionAlignment="center"
|
||||
cornerStyle="rounded"
|
||||
|
|
@ -26,6 +26,9 @@ defineRule('zip-format', regex(/(^\d{5}$)|(^\d{5}-\d{4}$)/, errorMessages.SERVIC
|
|||
|
||||
export default {
|
||||
name: 'service-zip-question',
|
||||
components: {
|
||||
textboxQuestion
|
||||
},
|
||||
props: {
|
||||
modelValue: {
|
||||
serviceZipCode: String
|
||||
|
|
@ -34,16 +37,13 @@ export default {
|
|||
},
|
||||
computed: {
|
||||
value: {
|
||||
get: function () {
|
||||
get() {
|
||||
return this.modelValue;
|
||||
},
|
||||
set: function (newValue) {
|
||||
set(newValue) {
|
||||
this.$emit('update:modelValue', newValue);
|
||||
}
|
||||
}
|
||||
},
|
||||
components: {
|
||||
textboxQuestion
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,41 +1,38 @@
|
|||
export const allGlassPartsAndItemsHavePrices = (lineItems) => {
|
||||
if (lineItems.glassParts && Array.isArray(lineItems.glassParts)) {
|
||||
if (!processLineItems(lineItems.glassParts))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
if (lineItems.supportingItems && Array.isArray(lineItems.supportingItems)) {
|
||||
if (!processLineItems(lineItems.supportingItems))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
if (lineItems.vaps && Array.isArray(lineItems.vaps)) {
|
||||
if (!processLineItems(lineItems.vaps))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
return true;
|
||||
const hasPrice = (lineItem) => {
|
||||
const value = (!!lineItem?.kitPrice && lineItem.kitPrice !== 0)
|
||||
|| (!!lineItem?.laborAmount && lineItem.laborAmount !== 0)
|
||||
|| (!!lineItem?.sellingPrice && lineItem.sellingPrice !== 0);
|
||||
return value;
|
||||
};
|
||||
|
||||
const processLineItems = (lineItems) => {
|
||||
let returnVal = true;
|
||||
lineItems.forEach( lineItem => {
|
||||
lineItems.forEach((lineItem) => {
|
||||
if (!hasPrice(lineItem)) {
|
||||
returnVal = false;
|
||||
};
|
||||
}
|
||||
});
|
||||
return returnVal;
|
||||
};
|
||||
|
||||
export const allGlassPartsAndItemsHavePrices = (lineItems) => {
|
||||
if (lineItems.glassParts && Array.isArray(lineItems.glassParts)) {
|
||||
if (!processLineItems(lineItems.glassParts)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const hasPrice = (lineItem) => {
|
||||
const value = (!!lineItem?.kitPrice && lineItem.kitPrice != 0) ||
|
||||
(!!lineItem?.laborAmount && lineItem.laborAmount != 0) ||
|
||||
(!!lineItem?.sellingPrice && lineItem.sellingPrice != 0);
|
||||
return value;
|
||||
if (lineItems.supportingItems && Array.isArray(lineItems.supportingItems)) {
|
||||
if (!processLineItems(lineItems.supportingItems)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (lineItems.vaps && Array.isArray(lineItems.vaps)) {
|
||||
if (!processLineItems(lineItems.vaps)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { allGlassPartsAndItemsHavePrices } from './service-package-helper';
|
|||
|
||||
it('service package helper should return false when line item has missing price', () => {
|
||||
// Arrange
|
||||
const mockData = { glassParts: [{partNumber: 'DW01571GBNNOEE', sellingPrice: 25}], supportingItems: [{ laborAmount: 0 }] }
|
||||
const mockData = { glassParts: [{ partNumber: 'DW01571GBNNOEE', sellingPrice: 25 }], supportingItems: [{ laborAmount: 0 }] };
|
||||
// Act
|
||||
const actual = allGlassPartsAndItemsHavePrices(mockData);
|
||||
// Assert
|
||||
|
|
@ -11,7 +11,7 @@ it('service package helper should return false when line item has missing price'
|
|||
|
||||
it('service package helper should return true when line item has all prices', () => {
|
||||
// Arrange
|
||||
const mockData = { glassParts: [{partNumber: 'DW01571GBNNOEE', sellingPrice: 25}], laborAmount: [{ sellingPrice: 10 }] }
|
||||
const mockData = { glassParts: [{ partNumber: 'DW01571GBNNOEE', sellingPrice: 25 }], laborAmount: [{ sellingPrice: 10 }] };
|
||||
// Act
|
||||
const actual = allGlassPartsAndItemsHavePrices(mockData);
|
||||
// Assert
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
<template>
|
||||
<buttonQuestion ref="buttonQuestion"
|
||||
<buttonQuestion
|
||||
ref="buttonQuestion"
|
||||
v-model="selectedPackageName"
|
||||
:answers="servicePackageAnswers"
|
||||
:groupName="groupName"
|
||||
buttonTypeString="servicePackageRadio"
|
||||
:buttonTypeObject="servicePackageRadio"
|
||||
v-model="selectedPackageName"
|
||||
:validationRules="validationRules"
|
||||
:isRequired="isRequired" />
|
||||
</template>
|
||||
|
|
@ -16,7 +17,7 @@ import { damageLocationsSelected as glassLocations } from '@/constants/damage-lo
|
|||
import servicePackageRadio from '@/layouts/service-packages/service-package-question/service-package-radio/service-package-radio';
|
||||
import { partTypeStrings } from '@/constants/part-type-strings';
|
||||
import { useMainStore } from '@/store';
|
||||
import { allGlassPartsAndItemsHavePrices } from '@/layouts/service-packages/service-package-helper/service-package-helper'
|
||||
import { allGlassPartsAndItemsHavePrices } from '@/layouts/service-packages/service-package-helper/service-package-helper';
|
||||
|
||||
const packageNames = {
|
||||
TIER_ONE: 'TierOne',
|
||||
|
|
@ -27,8 +28,10 @@ const packageNames = {
|
|||
const store = useMainStore();
|
||||
|
||||
export default {
|
||||
name: 'servicePackageQuestion',
|
||||
emits: ['vapsItemsSelected'],
|
||||
name: 'service-package-question',
|
||||
components: {
|
||||
buttonQuestion
|
||||
},
|
||||
props: {
|
||||
cmsWidgetName: String,
|
||||
groupName: String,
|
||||
|
|
@ -36,23 +39,13 @@ export default {
|
|||
isRequired: Boolean,
|
||||
availableLineItems: []
|
||||
},
|
||||
emits: ['vapsItemsSelected'],
|
||||
data() {
|
||||
return {
|
||||
servicePackageRadio: servicePackageRadio,
|
||||
servicePackageRadio,
|
||||
selectedPackageName: packageNames.TIER_ONE
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
availableLineItems() {
|
||||
if (allGlassPartsAndItemsHavePrices(store.order.lineItems)) {
|
||||
this.selectDefaultPackage();
|
||||
}
|
||||
},
|
||||
selectedPackageName(newValue) {
|
||||
const VapsProductsInSelectedPackage = this.getVapsLineItemsForSelectedPackage(newValue);
|
||||
this.$emit('vapsItemsSelected', VapsProductsInSelectedPackage);
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
nullSafeAvailableLineItems() {
|
||||
if (this.availableLineItems?.lineItems) {
|
||||
|
|
@ -64,27 +57,20 @@ export default {
|
|||
servicePackageAnswers() {
|
||||
if (!this.cmsWidgetName) return [];
|
||||
const cmsAnswersContent = [];
|
||||
cmsAnswersContent.push(
|
||||
{
|
||||
cmsAnswersContent.push({
|
||||
Name: 'TierOne',
|
||||
cmsWidgetName: 'EconomyServicePackage'
|
||||
}
|
||||
);
|
||||
if (this.shouldDisplayTierTwoPackage)
|
||||
{
|
||||
cmsAnswersContent.push(
|
||||
{
|
||||
});
|
||||
if (this.shouldDisplayTierTwoPackage) {
|
||||
cmsAnswersContent.push({
|
||||
Name: 'TierTwo',
|
||||
cmsWidgetName: 'StandardServicePackage'
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
cmsAnswersContent.push(
|
||||
{
|
||||
cmsAnswersContent.push({
|
||||
Name: 'TierThree',
|
||||
cmsWidgetName: 'PremiumServicePackage'
|
||||
}
|
||||
);
|
||||
});
|
||||
// if cms content has not yet loaded, skip
|
||||
if (this.getCmsContent(cmsAnswersContent[0].cmsWidgetName, 'HeaderText') == '') {
|
||||
return {};
|
||||
|
|
@ -104,24 +90,20 @@ export default {
|
|||
return this.lineItemsContainsPartType(partTypeStrings.RECALIBRATION);
|
||||
},
|
||||
frontWipersApplicableForTierTwo() {
|
||||
const frontWipersAreAvailable = this.lineItemsContainsPartType(
|
||||
partTypeStrings.FRONT_WIPER
|
||||
);
|
||||
const frontWipersAreAvailable = this.lineItemsContainsPartType(partTypeStrings.FRONT_WIPER);
|
||||
const glassToReplaceContainsWindshield = this.glassToReplaceContainsGlassLocation(glassLocations.WINDSHIELD);
|
||||
|
||||
if(frontWipersAreAvailable && (useMainStore().order.damage.isRepair || glassToReplaceContainsWindshield))
|
||||
{
|
||||
if (frontWipersAreAvailable && (useMainStore().order.damage.isRepair || glassToReplaceContainsWindshield)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
},
|
||||
rearWiperApplicableForTierTwo() {
|
||||
const rearWiperIsAvailable = this.lineItemsContainsPartType(partTypeStrings.REAR_WIPER);
|
||||
return (
|
||||
this.glassToReplaceContainsGlassLocation(glassLocations.REAR) &&
|
||||
rearWiperIsAvailable
|
||||
this.glassToReplaceContainsGlassLocation(glassLocations.REAR)
|
||||
&& rearWiperIsAvailable
|
||||
);
|
||||
},
|
||||
frontWipersApplicableForTierThree() {
|
||||
|
|
@ -132,26 +114,36 @@ export default {
|
|||
const rearWiperIsAvailable = this.lineItemsContainsPartType(partTypeStrings.REAR_WIPER);
|
||||
const frontWipersAreAvailable = this.lineItemsContainsPartType(partTypeStrings.FRONT_WIPER);
|
||||
return (
|
||||
rearWiperIsAvailable &&
|
||||
(this.glassToReplaceContainsGlassLocation(glassLocations.REAR) ||
|
||||
!frontWipersAreAvailable)
|
||||
rearWiperIsAvailable
|
||||
&& (this.glassToReplaceContainsGlassLocation(glassLocations.REAR)
|
||||
|| !frontWipersAreAvailable)
|
||||
);
|
||||
},
|
||||
rainDefenseApplicableForTierThree() {
|
||||
if (
|
||||
this.rearWiperApplicableForTierTwo &&
|
||||
!this.frontWipersApplicableForTierTwo &&
|
||||
this.frontWipersApplicableForTierThree
|
||||
this.rearWiperApplicableForTierTwo
|
||||
&& !this.frontWipersApplicableForTierTwo
|
||||
&& this.frontWipersApplicableForTierThree
|
||||
) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
shouldDisplayTierTwoPackage() {
|
||||
return this.frontWipersApplicableForTierTwo || this.rearWiperApplicableForTierTwo;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
availableLineItems() {
|
||||
if (allGlassPartsAndItemsHavePrices(store.order.lineItems)) {
|
||||
this.selectDefaultPackage();
|
||||
}
|
||||
},
|
||||
selectedPackageName(newValue) {
|
||||
const VapsProductsInSelectedPackage = this.getVapsLineItemsForSelectedPackage(newValue);
|
||||
this.$emit('vapsItemsSelected', VapsProductsInSelectedPackage);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
processIfStatements,
|
||||
getHeaderTextFromCms(cmsWidgetName) {
|
||||
|
|
@ -170,7 +162,7 @@ export default {
|
|||
},
|
||||
getPackagePriceString(packageName) {
|
||||
const formattedPriceFloat = parseFloat(this.getPackagePrice(packageName)).toFixed(2);
|
||||
return '+$' + formattedPriceFloat + '*';
|
||||
return `+$${formattedPriceFloat}*`;
|
||||
},
|
||||
getPackagePrice(packageName) {
|
||||
let priceFloat = 0;
|
||||
|
|
@ -187,9 +179,9 @@ export default {
|
|||
const priceRearWipers = this.rearWiperApplicableForTierTwo;
|
||||
this.nullSafeAvailableLineItems.forEach((item) => {
|
||||
if (
|
||||
(priceFrontWipers &&
|
||||
item.partType.toUpperCase() === partTypeStrings.FRONT_WIPER) ||
|
||||
(priceRearWipers && item.partType.toUpperCase() === partTypeStrings.REAR_WIPER)
|
||||
(priceFrontWipers
|
||||
&& item.partType.toUpperCase() === partTypeStrings.FRONT_WIPER)
|
||||
|| (priceRearWipers && item.partType.toUpperCase() === partTypeStrings.REAR_WIPER)
|
||||
) {
|
||||
vapsPrice += this.getTotalLineItemPrice(item);
|
||||
}
|
||||
|
|
@ -203,12 +195,12 @@ export default {
|
|||
const priceRainDefense = this.rainDefenseApplicableForTierThree;
|
||||
this.nullSafeAvailableLineItems.forEach((item) => {
|
||||
if (
|
||||
(priceFrontWipers &&
|
||||
item.partType.toUpperCase() === partTypeStrings.FRONT_WIPER) ||
|
||||
(priceRearWipers &&
|
||||
item.partType.toUpperCase() === partTypeStrings.REAR_WIPER) ||
|
||||
(priceRainDefense &&
|
||||
item.partType.toUpperCase() === partTypeStrings.RAIN_DEFENSE)
|
||||
(priceFrontWipers
|
||||
&& item.partType.toUpperCase() === partTypeStrings.FRONT_WIPER)
|
||||
|| (priceRearWipers
|
||||
&& item.partType.toUpperCase() === partTypeStrings.REAR_WIPER)
|
||||
|| (priceRainDefense
|
||||
&& item.partType.toUpperCase() === partTypeStrings.RAIN_DEFENSE)
|
||||
) {
|
||||
vapsPrice += this.getTotalLineItemPrice(item);
|
||||
}
|
||||
|
|
@ -220,16 +212,15 @@ export default {
|
|||
let lowestTierForPackage = packageNames.TIER_ONE;
|
||||
if (vapsFromStore?.length > 0) {
|
||||
vapsFromStore.every((vapsItem) => {
|
||||
let lowestTierForThisItem = this.getLowestTierForThisItem(vapsItem);
|
||||
const lowestTierForThisItem = this.getLowestTierForThisItem(vapsItem);
|
||||
if (lowestTierForThisItem === packageNames.TIER_THREE) {
|
||||
lowestTierForPackage = packageNames.TIER_THREE;
|
||||
return false;
|
||||
} else if (lowestTierForThisItem === packageNames.TIER_TWO) {
|
||||
} if (lowestTierForThisItem === packageNames.TIER_TWO) {
|
||||
lowestTierForPackage = packageNames.TIER_TWO;
|
||||
return true;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
this.selectedPackageName = lowestTierForPackage;
|
||||
|
|
@ -259,6 +250,7 @@ export default {
|
|||
lowestTierForThisItem = packageNames.TIER_THREE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
}
|
||||
return lowestTierForThisItem;
|
||||
},
|
||||
|
|
@ -266,30 +258,20 @@ export default {
|
|||
const vapsLineItemsForSelectedPackage = [];
|
||||
if (packageName === packageNames.TIER_TWO) {
|
||||
if (this.frontWipersApplicableForTierTwo) {
|
||||
vapsLineItemsForSelectedPackage.push(
|
||||
...this.getLineItemsContainingPartType(partTypeStrings.FRONT_WIPER)
|
||||
);
|
||||
vapsLineItemsForSelectedPackage.push(...this.getLineItemsContainingPartType(partTypeStrings.FRONT_WIPER));
|
||||
}
|
||||
if (this.rearWiperApplicableForTierTwo) {
|
||||
vapsLineItemsForSelectedPackage.push(
|
||||
...this.getLineItemsContainingPartType(partTypeStrings.REAR_WIPER)
|
||||
);
|
||||
vapsLineItemsForSelectedPackage.push(...this.getLineItemsContainingPartType(partTypeStrings.REAR_WIPER));
|
||||
}
|
||||
} else if (packageName === packageNames.TIER_THREE) {
|
||||
if (this.frontWipersApplicableForTierThree) {
|
||||
vapsLineItemsForSelectedPackage.push(
|
||||
...this.getLineItemsContainingPartType(partTypeStrings.FRONT_WIPER)
|
||||
);
|
||||
vapsLineItemsForSelectedPackage.push(...this.getLineItemsContainingPartType(partTypeStrings.FRONT_WIPER));
|
||||
}
|
||||
if (this.rearWiperApplicableForTierThree) {
|
||||
vapsLineItemsForSelectedPackage.push(
|
||||
...this.getLineItemsContainingPartType(partTypeStrings.REAR_WIPER)
|
||||
);
|
||||
vapsLineItemsForSelectedPackage.push(...this.getLineItemsContainingPartType(partTypeStrings.REAR_WIPER));
|
||||
}
|
||||
if (this.rainDefenseApplicableForTierThree) {
|
||||
vapsLineItemsForSelectedPackage.push(
|
||||
...this.getLineItemsContainingPartType(partTypeStrings.RAIN_DEFENSE)
|
||||
);
|
||||
vapsLineItemsForSelectedPackage.push(...this.getLineItemsContainingPartType(partTypeStrings.RAIN_DEFENSE));
|
||||
}
|
||||
}
|
||||
return vapsLineItemsForSelectedPackage;
|
||||
|
|
@ -313,9 +295,7 @@ export default {
|
|||
}
|
||||
},
|
||||
getLineItemsContainingPartType(partType) {
|
||||
const partTypeMatches = this.nullSafeAvailableLineItems.filter(
|
||||
(lineItem) => lineItem.partType.toUpperCase() === partType
|
||||
);
|
||||
const partTypeMatches = this.nullSafeAvailableLineItems.filter((lineItem) => lineItem.partType.toUpperCase() === partType);
|
||||
return partTypeMatches;
|
||||
},
|
||||
lineItemsContainsPartType(partType) {
|
||||
|
|
@ -324,18 +304,13 @@ export default {
|
|||
},
|
||||
glassToReplaceContainsGlassLocation(glassLocation) {
|
||||
const store = useMainStore();
|
||||
const glassLocationMatches =
|
||||
store.order.damage.glassToReplace?.filter(
|
||||
(glassToReplace) => glassToReplace.glassLocation === glassLocation
|
||||
) ?? [];
|
||||
const glassLocationMatches
|
||||
= store.order.damage.glassToReplace?.filter((glassToReplace) => glassToReplace.glassLocation === glassLocation) ?? [];
|
||||
return !!glassLocationMatches.length;
|
||||
},
|
||||
getTotalLineItemPrice(lineItem) {
|
||||
return lineItem.kitPrice + lineItem.laborAmount + lineItem.sellingPrice;
|
||||
}
|
||||
},
|
||||
components: {
|
||||
buttonQuestion
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,113 +1,6 @@
|
|||
import { mount } from '@vue/test-utils';
|
||||
import servicePackageRadio from './service-package-radio';
|
||||
import inputButtonWrapperMixin from '@/mixins/input-button-wrapper-mixin';
|
||||
|
||||
describe('service-package-radio.vue', () => {
|
||||
it('Should include buttonLabel in html', async () => {
|
||||
// Arrange
|
||||
let { wrapper } = setupMocks({
|
||||
mountOptionsMockData: {
|
||||
propsData: mockProps,
|
||||
}
|
||||
});
|
||||
|
||||
// Act
|
||||
const outputHtml = wrapper.html();
|
||||
|
||||
// Assert
|
||||
expect(outputHtml).toEqual(expect.stringContaining(mockProps['buttonLabel']));
|
||||
});
|
||||
|
||||
it('Should include buttonLabelAuxillaryCopy in html', async () => {
|
||||
// Arrange
|
||||
let { wrapper } = setupMocks({
|
||||
mountOptionsMockData: {
|
||||
propsData: mockProps,
|
||||
}
|
||||
});
|
||||
|
||||
// Act
|
||||
const outputHtml = wrapper.html();
|
||||
|
||||
// Assert
|
||||
expect(outputHtml).toEqual(expect.stringContaining(mockProps['buttonLabelAuxillaryCopy']));
|
||||
});
|
||||
|
||||
it('Should include buttonLabelSubCopy in html', async () => {
|
||||
// Arrange
|
||||
let { wrapper } = setupMocks({
|
||||
mountOptionsMockData: {
|
||||
propsData: mockProps,
|
||||
}
|
||||
});
|
||||
|
||||
// Act
|
||||
const outputHtml = wrapper.html();
|
||||
|
||||
// Assert
|
||||
expect(outputHtml).toEqual(expect.stringContaining(mockProps['buttonLabelSubCopy']));
|
||||
});
|
||||
it('Should include buttonFooterCopy in html', async () => {
|
||||
// Arrange
|
||||
let { wrapper } = setupMocks({
|
||||
mountOptionsMockData: {
|
||||
propsData: mockProps,
|
||||
}
|
||||
});
|
||||
|
||||
// Act
|
||||
const outputHtml = wrapper.html();
|
||||
|
||||
// Assert
|
||||
expect(outputHtml).toEqual(expect.stringContaining(mockProps['buttonFooterCopy']));
|
||||
});
|
||||
it('Should get 5 strings from getArrayOfListItemsFromRawCmsCopy when provided with a dashed (x5) buttonBodyCopy', async () => {
|
||||
// Arrange
|
||||
let { wrapper } = setupMocks({
|
||||
mountOptionsMockData: {
|
||||
propsData: mockProps,
|
||||
}
|
||||
});
|
||||
// Act
|
||||
const results = wrapper.vm.getArrayOfListItemsFromRawCmsCopy(wrapper.vm.buttonBodyCopy);
|
||||
|
||||
// Assert
|
||||
expect(results.length).toBe(5);
|
||||
});
|
||||
it('Should get strings from getArrayOfListItemsFromRawCmsCopy without dashes when provided with a dashed buttonBodyCopy', async () => {
|
||||
// Arrange
|
||||
let { wrapper } = setupMocks({
|
||||
mountOptionsMockData: {
|
||||
propsData: mockProps,
|
||||
}
|
||||
});
|
||||
|
||||
// Act
|
||||
const results = wrapper.vm.getArrayOfListItemsFromRawCmsCopy(wrapper.vm.buttonBodyCopy);
|
||||
|
||||
// Assert
|
||||
const fileredResults = results.filter((result) => {
|
||||
return result.includes(' -');
|
||||
});
|
||||
expect(fileredResults.length).toBe(0);
|
||||
});
|
||||
it('Should get 5 strings from getArrayOfListItemsFromRawCmsCopy when buttonBodyCopy has 6 total dashes, but one is empty ', async () => {
|
||||
// Arrange
|
||||
const moddedProps = mockProps;
|
||||
moddedProps['buttonBodyCopy'] = '- buttonBodyCopy test copy - 2 - 3 - 4 - 5 -';
|
||||
let { wrapper } = setupMocks({
|
||||
mountOptionsMockData: {
|
||||
propsData: moddedProps
|
||||
}
|
||||
});
|
||||
|
||||
// Act
|
||||
const results = wrapper.vm.getArrayOfListItemsFromRawCmsCopy(wrapper.vm.buttonBodyCopy);
|
||||
|
||||
// Assert
|
||||
expect(results.length).toBe(5);
|
||||
});
|
||||
});
|
||||
import servicePackageRadio from './service-package-radio';
|
||||
|
||||
const mockProps = {
|
||||
buttonLabel: 'buttonLabel test copy',
|
||||
|
|
@ -125,3 +18,109 @@ function setupMocks({ mountOptionsMockData = {} }) {
|
|||
|
||||
return { wrapper };
|
||||
}
|
||||
|
||||
describe('service-package-radio.vue', () => {
|
||||
it('Should include buttonLabel in html', async () => {
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({
|
||||
mountOptionsMockData: {
|
||||
propsData: mockProps
|
||||
}
|
||||
});
|
||||
|
||||
// Act
|
||||
const outputHtml = wrapper.html();
|
||||
|
||||
// Assert
|
||||
expect(outputHtml).toEqual(expect.stringContaining(mockProps.buttonLabel));
|
||||
});
|
||||
|
||||
it('Should include buttonLabelAuxillaryCopy in html', async () => {
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({
|
||||
mountOptionsMockData: {
|
||||
propsData: mockProps
|
||||
}
|
||||
});
|
||||
|
||||
// Act
|
||||
const outputHtml = wrapper.html();
|
||||
|
||||
// Assert
|
||||
expect(outputHtml).toEqual(expect.stringContaining(mockProps.buttonLabelAuxillaryCopy));
|
||||
});
|
||||
|
||||
it('Should include buttonLabelSubCopy in html', async () => {
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({
|
||||
mountOptionsMockData: {
|
||||
propsData: mockProps
|
||||
}
|
||||
});
|
||||
|
||||
// Act
|
||||
const outputHtml = wrapper.html();
|
||||
|
||||
// Assert
|
||||
expect(outputHtml).toEqual(expect.stringContaining(mockProps.buttonLabelSubCopy));
|
||||
});
|
||||
it('Should include buttonFooterCopy in html', async () => {
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({
|
||||
mountOptionsMockData: {
|
||||
propsData: mockProps
|
||||
}
|
||||
});
|
||||
|
||||
// Act
|
||||
const outputHtml = wrapper.html();
|
||||
|
||||
// Assert
|
||||
expect(outputHtml).toEqual(expect.stringContaining(mockProps.buttonFooterCopy));
|
||||
});
|
||||
it('Should get 5 strings from getArrayOfListItemsFromRawCmsCopy when provided with a dashed (x5) buttonBodyCopy', async () => {
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({
|
||||
mountOptionsMockData: {
|
||||
propsData: mockProps
|
||||
}
|
||||
});
|
||||
// Act
|
||||
const results = wrapper.vm.getArrayOfListItemsFromRawCmsCopy(wrapper.vm.buttonBodyCopy);
|
||||
|
||||
// Assert
|
||||
expect(results.length).toBe(5);
|
||||
});
|
||||
it('Should get strings from getArrayOfListItemsFromRawCmsCopy without dashes when provided with a dashed buttonBodyCopy', async () => {
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({
|
||||
mountOptionsMockData: {
|
||||
propsData: mockProps
|
||||
}
|
||||
});
|
||||
|
||||
// Act
|
||||
const results = wrapper.vm.getArrayOfListItemsFromRawCmsCopy(wrapper.vm.buttonBodyCopy);
|
||||
|
||||
// Assert
|
||||
const fileredResults = results.filter((result) => result.includes(' -'));
|
||||
expect(fileredResults.length).toBe(0);
|
||||
});
|
||||
it('Should get 5 strings from getArrayOfListItemsFromRawCmsCopy when buttonBodyCopy has 6 total dashes, but one is empty ',
|
||||
async () => {
|
||||
// Arrange
|
||||
const moddedProps = mockProps;
|
||||
moddedProps.buttonBodyCopy = '- buttonBodyCopy test copy - 2 - 3 - 4 - 5 -';
|
||||
const { wrapper } = setupMocks({
|
||||
mountOptionsMockData: {
|
||||
propsData: moddedProps
|
||||
}
|
||||
});
|
||||
|
||||
// Act
|
||||
const results = wrapper.vm.getArrayOfListItemsFromRawCmsCopy(wrapper.vm.buttonBodyCopy);
|
||||
|
||||
// Assert
|
||||
expect(results.length).toBe(5);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,43 +1,58 @@
|
|||
<template>
|
||||
<baseInputButton v-bind="$props" v-model="selectedValue">
|
||||
<div class="package-label mb-4"
|
||||
:class="[this.buttonLabelSubCopy ? 'has-subheader' : '']"
|
||||
<baseInputButton
|
||||
v-bind="$props"
|
||||
v-model="selectedValue">
|
||||
<div
|
||||
class="package-label mb-4"
|
||||
:class="[buttonLabelSubCopy ? 'has-subheader' : '']"
|
||||
for="testradio">
|
||||
<div class="package-specs">
|
||||
<p class="m-0">
|
||||
<span v-html="this.buttonLabel"></span>
|
||||
<span class="pricing-info" v-html="this.buttonAuxiliaryCopy"></span>
|
||||
<span v-html="buttonLabel"></span>
|
||||
<span
|
||||
class="pricing-info"
|
||||
v-html="buttonAuxiliaryCopy"></span>
|
||||
</p>
|
||||
<p class="sub-label m-0"
|
||||
v-if="this.buttonLabelSubCopy"
|
||||
v-html="this.buttonLabelSubCopy"></p>
|
||||
<p
|
||||
v-if="buttonLabelSubCopy"
|
||||
class="sub-label m-0"
|
||||
v-html="buttonLabelSubCopy"></p>
|
||||
<div>
|
||||
<ul>
|
||||
<li v-for="listItem in this.arrayOfListItemsFromBodyText" :key="listItem" class="mb-0">
|
||||
<li
|
||||
v-for="listItem in arrayOfListItemsFromBodyText"
|
||||
:key="listItem"
|
||||
class="mb-0">
|
||||
<!-- no textLink -->
|
||||
<span v-if="!doesCopyContainTextLink(listItem)"
|
||||
<span
|
||||
v-if="!doesCopyContainTextLink(listItem)"
|
||||
v-html="listItem"></span>
|
||||
<!-- with textLink -->
|
||||
<template v-else
|
||||
<template
|
||||
v-for="copy in splitCopyOnCMSPlaceHolder(listItem)"
|
||||
v-else
|
||||
:key="copy">
|
||||
<span v-if="!doesCopyContainTextLink(copy)" v-html="copy"></span>
|
||||
<span
|
||||
v-if="!doesCopyContainTextLink(copy)"
|
||||
v-html="copy"></span>
|
||||
<span v-else>
|
||||
<textLink linkType="text"
|
||||
<textLink
|
||||
linkType="text"
|
||||
:text="getRouterLinkDisplayTextFromCopy(copy)"
|
||||
href="#!"
|
||||
@click-event="textLinkEmit(copy)"
|
||||
:data-bs-target="'#' + getRouterLinkRouteFromCopy(copy)"
|
||||
aria-label="Modal window" />
|
||||
aria-label="Modal window"
|
||||
@click-event="textLinkEmit(copy)" />
|
||||
</span>
|
||||
</template>
|
||||
</li>
|
||||
</ul>
|
||||
<!-- End of body text parsing -->
|
||||
<!--ms-n6-->
|
||||
<div class="package-footer fw-bold caption mt-4 ml-n4 mr-3"
|
||||
v-if="this.buttonFooterCopy"
|
||||
v-html="this.buttonFooterCopy"></div>
|
||||
<div
|
||||
v-if="buttonFooterCopy"
|
||||
class="package-footer fw-bold caption mt-4 ml-n4 mr-3"
|
||||
v-html="buttonFooterCopy"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -54,14 +69,15 @@ import {
|
|||
splitCopyOnCMSPlaceHolder,
|
||||
doesCopyContainTextLink
|
||||
} from '@/helpers/cms-content-helper';
|
||||
|
||||
export default {
|
||||
name: 'servicePackageRadio',
|
||||
emits:['link-event'],
|
||||
mixins: [inputButtonWrapperMixin],
|
||||
name: 'service-package-radio',
|
||||
components: {
|
||||
baseInputButton,
|
||||
textLink
|
||||
},
|
||||
mixins: [inputButtonWrapperMixin],
|
||||
emits: ['link-event'],
|
||||
computed: {
|
||||
arrayOfListItemsFromBodyText() {
|
||||
return this.getArrayOfListItemsFromRawCmsCopy(this.buttonBodyCopy);
|
||||
|
|
@ -81,6 +97,7 @@ export default {
|
|||
.split('- ') // At some point we'll want a better delimiter
|
||||
.filter((lineItem) => lineItem);
|
||||
}
|
||||
return null;
|
||||
},
|
||||
textLinkEmit(copy) {
|
||||
this.$parent.$emit('link-event', {
|
||||
|
|
|
|||
|
|
@ -1,24 +1,31 @@
|
|||
<template>
|
||||
<Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm" v-slot="{ meta }">
|
||||
<Form
|
||||
ref="theForm"
|
||||
v-slot="{ meta }"
|
||||
@submit="onSubmit"
|
||||
@invalid-submit="onInvalidSubmit">
|
||||
<div class="page-container-grouped-styles">
|
||||
<div class="fade-on-route-transition sub-container make-tall">
|
||||
<siteHeader cmsWidgetName="SiteHeaderWidget" />
|
||||
<siteSubHeader cmsWidgetName="SiteSubHeaderWidget"
|
||||
<siteSubHeader
|
||||
cmsWidgetName="SiteSubHeaderWidget"
|
||||
justification="left"
|
||||
issContainingPage="service-packages"
|
||||
/>
|
||||
issContainingPage="service-packages" />
|
||||
<div class="mx-5">
|
||||
<servicePackageQuestion ref="servicePackage"
|
||||
<servicePackageQuestion
|
||||
ref="servicePackage"
|
||||
cmsWidgetName="ServicePackage"
|
||||
groupName="ServicePackageQuestion"
|
||||
:availableLineItems="availableLineItems"
|
||||
@vapsItemsSelected="vapsItemsSelectedAction"
|
||||
v-on:link-event="openModalAction"
|
||||
:validationRules="rules.optionRequired"
|
||||
isRequired
|
||||
/>
|
||||
<p class="caption disclaimer" v-html="PriceDisclaimerText"></p>
|
||||
<siteFooter cmsWidgetName="SiteFooterWidget"
|
||||
@vapsItemsSelected="vapsItemsSelectedAction"
|
||||
@link-event="openModalAction" />
|
||||
<p
|
||||
class="caption disclaimer"
|
||||
v-html="PriceDisclaimerText"></p>
|
||||
<siteFooter
|
||||
cmsWidgetName="SiteFooterWidget"
|
||||
:isForwardActionDisabled="!meta.valid"
|
||||
@back-clicked="backButtonAction"
|
||||
@ForwardClicked="forwardButtonAction" />
|
||||
|
|
@ -26,12 +33,18 @@
|
|||
</div>
|
||||
</div>
|
||||
<loadingModal ref="loadingModal" />
|
||||
<contentGroupModal ref="RainDefenseModal" cmsWidgetName="RainDefenseModal" />
|
||||
<contentGroupModal ref="FrontWiperModal" cmsWidgetName="FrontWiperModal" />
|
||||
<contentGroupModal ref="RearWiperModal" cmsWidgetName="RearWiperModal" />
|
||||
<contentGroupModal ref="RecalModal" cmsWidgetName="RecalModal" />
|
||||
|
||||
|
||||
<contentGroupModal
|
||||
ref="RainDefenseModal"
|
||||
cmsWidgetName="RainDefenseModal" />
|
||||
<contentGroupModal
|
||||
ref="FrontWiperModal"
|
||||
cmsWidgetName="FrontWiperModal" />
|
||||
<contentGroupModal
|
||||
ref="RearWiperModal"
|
||||
cmsWidgetName="RearWiperModal" />
|
||||
<contentGroupModal
|
||||
ref="RecalModal"
|
||||
cmsWidgetName="RecalModal" />
|
||||
</Form>
|
||||
</template>
|
||||
|
||||
|
|
@ -41,23 +54,31 @@ import baseFormMixin from '@/mixins/base-form-mixin';
|
|||
import siteHeader from '@/iss-components/site-header/site-header';
|
||||
import siteFooter from '@/iss-components/site-footer/site-footer';
|
||||
import siteSubHeader from '@/iss-components/site-sub-header/site-sub-header';
|
||||
import servicePackageQuestion from './service-package-question/service-package-question';
|
||||
import textBlock from '@/digital-components/text-block/text-block';
|
||||
import contentGroupModal from '@/iss-components/content-group-modal/content-group-modal';
|
||||
import loadingModal from '@/iss-components/loading-modal/loading-modal.vue';
|
||||
import loadingModal from '@/iss-components/loading-modal/loading-modal';
|
||||
import { settleAllPromises } from '@/helpers/layout-helper';
|
||||
import { useMainStore } from '@/store';
|
||||
import { fetchCmsContentForPage } from '@/helpers/cms-content-helper';
|
||||
import { required } from '@/helpers/validation-rules';
|
||||
import { errorMessages } from '@/constants/error-messages';
|
||||
import { Form, defineRule } from 'vee-validate';
|
||||
import { allGlassPartsAndItemsHavePrices } from '@/layouts/service-packages/service-package-helper/service-package-helper'
|
||||
import { Form } from 'vee-validate';
|
||||
import { allGlassPartsAndItemsHavePrices } from '@/layouts/service-packages/service-package-helper/service-package-helper';
|
||||
import globalRules from '@/constants/global-rules';
|
||||
import servicePackageQuestion from './service-package-question/service-package-question';
|
||||
|
||||
const store = useMainStore();
|
||||
|
||||
export default {
|
||||
name: 'service-packages',
|
||||
components: {
|
||||
siteHeader,
|
||||
siteFooter,
|
||||
siteSubHeader,
|
||||
// eslint-disable-next-line vue/no-reserved-component-names
|
||||
Form,
|
||||
servicePackageQuestion,
|
||||
loadingModal,
|
||||
contentGroupModal
|
||||
},
|
||||
mixins: [baseFormMixin],
|
||||
async beforeRouteEnter(to, from, next) {
|
||||
// Call APIs
|
||||
|
|
@ -128,12 +149,12 @@ export default {
|
|||
},
|
||||
arePagePrerequisitesValid() {
|
||||
return (
|
||||
store.order.serviceLocation.zipCode &&
|
||||
store.order.serviceLocation.zipCodeCtu &&
|
||||
(store.order.damage.isRepair ||
|
||||
(store.order.lineItems?.glassParts != null &&
|
||||
store.order.lineItems.glassParts.length > 0)) &&
|
||||
store.order.referralNumber?.length !== 6
|
||||
store.order.serviceLocation.zipCode
|
||||
&& store.order.serviceLocation.zipCodeCtu
|
||||
&& (store.order.damage.isRepair
|
||||
|| (store.order.lineItems?.glassParts != null
|
||||
&& store.order.lineItems.glassParts.length > 0))
|
||||
&& store.order.referralNumber?.length !== 6
|
||||
);
|
||||
},
|
||||
vapsItemsSelectedAction(vapsItemsSelected) {
|
||||
|
|
@ -155,21 +176,11 @@ export default {
|
|||
|
||||
this.$router.navigate(this.navigationScenarios.CLICKED_FORWARD, this.$route);
|
||||
}
|
||||
},
|
||||
components: {
|
||||
siteHeader,
|
||||
siteFooter,
|
||||
siteSubHeader,
|
||||
Form, /* eslint-disable-line */
|
||||
textBlock,
|
||||
servicePackageQuestion,
|
||||
loadingModal,
|
||||
contentGroupModal
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
<style lang="scss" scoped>
|
||||
.subheader-secondary {
|
||||
margin-top: .5rem;
|
||||
padding: 0px;
|
||||
|
|
|
|||
Loading…
Reference in a new issue