commit
a4eea34737
8 changed files with 308 additions and 13 deletions
161
src/layouts/provider-preference/provider-preference.spec.js
Normal file
161
src/layouts/provider-preference/provider-preference.spec.js
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
import { mount } from '@vue/test-utils';
|
||||
import { navigationScenarios } from '@/router/router-constants/navigation-scenarios';
|
||||
import { issPageValues } from '@/router/router-constants/issPage-values';
|
||||
import { queryStrings } from '@/constants/query-strings';
|
||||
import { GaActions } from "@/constants/analytics";
|
||||
import ProviderPreference from "@/layouts/provider-preference/provider-preference.vue"
|
||||
import { useMainStore } from '@/store';
|
||||
import { createTestingPinia } from '@pinia/testing';
|
||||
import { mapStores } from "pinia";
|
||||
|
||||
const pinia = createTestingPinia();
|
||||
useMainStore(pinia);
|
||||
|
||||
const ProviderPreferenceMockData = {
|
||||
QuestionText: 'Which auto glass shop would you like to work with?',
|
||||
Answers: [
|
||||
{
|
||||
Name: 'Schedule with Safelite',
|
||||
Text: 'Schedule with Safelite',
|
||||
SubText: '',
|
||||
ImageId: '',
|
||||
SubWidgetName: '',
|
||||
},
|
||||
{
|
||||
Name: 'Find another shop',
|
||||
Text: 'Find another shop',
|
||||
SubText: '',
|
||||
ImageId: '',
|
||||
SubWidgetName: '',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const siteFooterWidgetMockData = {
|
||||
ForwardButtonText: 'Continue',
|
||||
};
|
||||
|
||||
function setupMocks() {
|
||||
const mockRoute = {
|
||||
query: {
|
||||
issPage: 'provider-preference',
|
||||
},
|
||||
};
|
||||
|
||||
const mockRouter = {
|
||||
navigate: jest.fn(),
|
||||
};
|
||||
|
||||
const wrapper = mount(ProviderPreference, {
|
||||
data() {
|
||||
return {
|
||||
SelectedshopLocation: null,
|
||||
};
|
||||
},
|
||||
global: {
|
||||
mixins: [
|
||||
{
|
||||
computed: {
|
||||
...mapStores(useMainStore),
|
||||
GaActions() {
|
||||
return GaActions;
|
||||
},
|
||||
queryStrings() {
|
||||
return queryStrings;
|
||||
},
|
||||
navigationScenarios() {
|
||||
return navigationScenarios;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
getCmsContent: jest.fn((cmsWidgetName, fieldName) => {
|
||||
if (cmsWidgetName === 'SiteFooterWidget') {
|
||||
if (fieldName === 'ForwardButtonText') {
|
||||
return siteFooterWidgetMockData.ForwardButtonText;
|
||||
}
|
||||
}
|
||||
|
||||
if (cmsWidgetName === 'ProviderPreference') {
|
||||
if (fieldName === 'QuestionText') {
|
||||
return ProviderPreferenceMockData.QuestionText;
|
||||
}
|
||||
if (fieldName === 'Answers') {
|
||||
return ProviderPreferenceMockData.Answers;
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
}),
|
||||
getFooterInfoBoxHeight: jest.fn(() => 80),
|
||||
getPageNameByQueryString: jest.fn(() => "provider-preference"),
|
||||
pushEventToGA: jest.fn(),
|
||||
},
|
||||
},
|
||||
],
|
||||
mocks: {
|
||||
$route: mockRoute,
|
||||
$router: mockRouter,
|
||||
},
|
||||
stubs: {
|
||||
SiteHeader: true,
|
||||
SiteSubHeader: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
return { mockRoute, mockRouter, wrapper };
|
||||
}
|
||||
describe('provider-preference.vue', () => {
|
||||
test('"Continue" button is disabled when no Shop Location is selected.', () => {
|
||||
const { wrapper } = setupMocks();
|
||||
|
||||
const continueButton = wrapper.get('[data-test-id="site-footer-main-button"]');
|
||||
expect(continueButton.attributes()['aria-disabled']).toBe('true');
|
||||
});
|
||||
test('"Continue" button is enabled after a Shop Location is selected.', async () => {
|
||||
const { wrapper } = setupMocks();
|
||||
|
||||
const ProviderPreferenceWrapper = wrapper.findComponent({ name: 'provider-preference' });
|
||||
// Not using initializeComponent() because it doesn't trigger reactivity in test.
|
||||
await ProviderPreferenceWrapper.setData({
|
||||
questionTextFromCms: ProviderPreferenceMockData.QuestionText,
|
||||
answersFromCms: ProviderPreferenceMockData.Answers,
|
||||
SelectedshopLocation:"Schedule with Safelite"
|
||||
});
|
||||
|
||||
|
||||
const continueButton = wrapper.get('[data-test-id="site-footer-main-button"]');
|
||||
expect(continueButton.attributes()['aria-disabled']).toBe('false');
|
||||
});
|
||||
test('Select "Schedule with Safelite" then click "Continue". Navigates to "service-location" page.', async () => {
|
||||
const { mockRoute, mockRouter, wrapper } = setupMocks();
|
||||
|
||||
const ProviderPreferenceWrapper = wrapper.findComponent({ name: 'provider-preference' });
|
||||
// Not using initializeComponent() because it doesn't trigger reactivity in test.
|
||||
await ProviderPreferenceWrapper.setData({
|
||||
questionTextFromCms: ProviderPreferenceMockData.QuestionText,
|
||||
answersFromCms: ProviderPreferenceMockData.Answers,
|
||||
SelectedshopLocation:"Schedule with Safelite"
|
||||
});
|
||||
|
||||
const continueButton = wrapper.get('[data-test-id="site-footer-main-button"]');
|
||||
await continueButton.trigger('click');
|
||||
|
||||
expect(mockRouter.navigate).toHaveBeenCalledTimes(1);
|
||||
expect(mockRouter.navigate)
|
||||
.toHaveBeenCalledWith(navigationScenarios.CLICKED_FORWARD_WITH_SAFELITE, mockRoute);
|
||||
/**
|
||||
* To Do: find a way to confirm that Vue Router really routes to the expected page.
|
||||
* Currently just trust that our custom navigate() method does its job properly.
|
||||
*/
|
||||
});
|
||||
|
||||
test('Click the back button, trigger navigate function from Vue Router with CLICKED_BACK parameter.', async () => {
|
||||
const { mockRoute, mockRouter, wrapper } = setupMocks();
|
||||
|
||||
await wrapper.get('[data-test-id="site-footer-back-button"]').trigger('click');
|
||||
expect(mockRouter.navigate).toHaveBeenCalledTimes(1);
|
||||
expect(mockRouter.navigate)
|
||||
.toHaveBeenCalledWith(navigationScenarios.CLICKED_BACK, mockRoute);
|
||||
});
|
||||
});
|
||||
|
|
@ -17,11 +17,12 @@
|
|||
:answers="answersFromCms"
|
||||
buttonTypeString="listButton"
|
||||
isRequired
|
||||
v-model="SelectedshopLocation"
|
||||
validationRules="questions-required" />
|
||||
|
||||
<siteFooter
|
||||
cmsWidgetName="SiteFooterWidget"
|
||||
:isForwardActionDisabled="!meta.valid"
|
||||
:isForwardActionDisabled="isForwardActionDisabled"
|
||||
@backClicked="backButtonAction"
|
||||
@forwardClicked="forwardButtonAction"
|
||||
ref="siteFooter"
|
||||
|
|
@ -50,10 +51,8 @@ import shoppreferenceModal from '@/layouts/provider-preference/shoppreference-mo
|
|||
defineRule("questions-required", required(errorMessages.OPTION_REQUIRED));
|
||||
export default {
|
||||
name: "provider-preference",
|
||||
props:{
|
||||
//answersToDisplay: Array
|
||||
},
|
||||
mixins: [baseFormMixin],
|
||||
|
||||
components: {
|
||||
siteFooter,
|
||||
siteHeader,
|
||||
|
|
@ -63,7 +62,9 @@ export default {
|
|||
buttonQuestion
|
||||
},
|
||||
data() {
|
||||
return {};
|
||||
return {
|
||||
SelectedshopLocation : null,
|
||||
};
|
||||
},
|
||||
async beforeRouteEnter(to, from, next) {
|
||||
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
|
||||
|
|
@ -80,11 +81,14 @@ export default {
|
|||
});
|
||||
},
|
||||
computed: {
|
||||
isForwardActionDisabled() {
|
||||
return this.SelectedshopLocation === null;
|
||||
},
|
||||
ProviderPreferenceHeaderText(){
|
||||
return this.getCmsContent("ProviderPreference", "HeaderText");
|
||||
},
|
||||
ProviderPreferenceBodyText(){
|
||||
return this.getCmsContent("ProviderPreference", "BodyText");
|
||||
return this.getCmsContent("ProviderPreference", "BodyText");
|
||||
},
|
||||
questionText() {
|
||||
return this.getCmsContent("ServiceLocationQuestion", "QuestionText");
|
||||
|
|
@ -103,7 +107,12 @@ export default {
|
|||
*/
|
||||
this.$router.navigate(this.navigationScenarios.CLICKED_BACK, this.$route);
|
||||
},
|
||||
async forwardButtonAction() {},
|
||||
forwardButtonAction() {
|
||||
if(this.SelectedshopLocation == "Schedule with Safelite")
|
||||
{
|
||||
this.$router.navigate(this.navigationScenarios.CLICKED_FORWARD_WITH_SAFELITE, this.$route);
|
||||
}
|
||||
},
|
||||
resetDependentState() {},
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,41 @@
|
|||
import { shallowMount } from "@vue/test-utils";
|
||||
import shoppreferenceModal from '@/layouts/provider-preference/shoppreference-modal/shoppreference-modal.vue';
|
||||
|
||||
describe("modal.vue", () => {
|
||||
it("Should display header text when HeaderText is defined in the CMS", async () => {
|
||||
// Act
|
||||
const wrapper = shallowMount(shoppreferenceModal, {
|
||||
mixins: [mockMixin],
|
||||
props: {
|
||||
cmsWidgetName: "test",
|
||||
},
|
||||
attachTo: document.body,
|
||||
});
|
||||
expect(wrapper.html()).toEqual(expect.stringContaining(mockCmsContent["HeaderText"]));
|
||||
});
|
||||
|
||||
it("Should display body text when BodyText is defined in the CMS", async () => {
|
||||
// Act
|
||||
const wrapper = shallowMount(shoppreferenceModal, {
|
||||
mixins: [mockMixin],
|
||||
props: {
|
||||
cmsWidgetName: "test",
|
||||
},
|
||||
attachTo: document.body,
|
||||
});
|
||||
expect(wrapper.html()).toEqual(expect.stringContaining(mockCmsContent["BodyText"]));
|
||||
});
|
||||
});
|
||||
const mockMixin = {
|
||||
methods: {
|
||||
getCmsContent: jest.fn((widgetName, cmsFieldName) => {
|
||||
return mockCmsContent[cmsFieldName];
|
||||
}),
|
||||
},
|
||||
};
|
||||
|
||||
const mockCmsContent = {
|
||||
HeaderText: "Sample header text here.",
|
||||
BodyText: "Sample body text here.",
|
||||
FooterText: "Sample footer text here.",
|
||||
};
|
||||
|
|
@ -18,7 +18,7 @@
|
|||
</div>
|
||||
<div class="modal-body ps-4 pe-4 pt-4 pb-4">
|
||||
<h5 class="mb-4 text-center header-text" v-html="ModalHeadline"></h5>
|
||||
<p class="mb-2 subheader-text" v-html="ModalSubheadertext"></p>
|
||||
<p class="mb-0 small" v-html="ModalBodyText"></p>
|
||||
</div>
|
||||
<div class="modal-footer px-5 py-4">
|
||||
<buttonMain
|
||||
|
|
@ -47,8 +47,8 @@ export default {
|
|||
ModalHeadline() {
|
||||
return this.getCmsContent(this.cmsWidgetName, "HeaderText");
|
||||
},
|
||||
ModalSubheadertext() {
|
||||
return this.getCmsContent(this.cmsWidgetName, "SubheaderText");
|
||||
ModalBodyText() {
|
||||
return this.getCmsContent(this.cmsWidgetName, "BodyText");
|
||||
},
|
||||
ModalCloseButtonText() {
|
||||
return this.getCmsContent(this.cmsWidgetName, "FooterText");
|
||||
|
|
@ -76,9 +76,6 @@ export default {
|
|||
font-weight: 500;
|
||||
|
||||
}
|
||||
.subheader-text {
|
||||
color: #525656;
|
||||
}
|
||||
.modal-header {
|
||||
border-bottom: none;
|
||||
.btn-close {
|
||||
|
|
|
|||
71
src/layouts/service-location/service-location.vue
Normal file
71
src/layouts/service-location/service-location.vue
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
<template>
|
||||
<div>
|
||||
<Form @submit="onSubmit" @invalidSubmit="onInvalidSubmit" v-slot="{ meta }">
|
||||
<div class="page-container-grouped-styles overflow-auto">
|
||||
<siteHeader cmsWidgetName="SiteHeaderWidget" />
|
||||
<siteSubHeader cmsWidgetName="SiteSubHeaderWidget" />
|
||||
<div class="fade-on-route-transition sub-container make-tall px-5">
|
||||
<p>Placeholder for service-location page</p>
|
||||
<siteFooter
|
||||
cmsWidgetName="SiteFooterWidget"
|
||||
:isForwardActionDisabled="!meta.valid"
|
||||
@backClicked="backButtonAction"
|
||||
@forwardClicked="forwardButtonAction"
|
||||
ref="siteFooter"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Form>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
// Import Supporting Files
|
||||
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
|
||||
import { settleAllPromises } from "@/helpers/layout-helper";
|
||||
// Import Component
|
||||
import baseFormMixin from "@/mixins/base-form-mixin";
|
||||
import { Form } 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";
|
||||
export default {
|
||||
name: "provider-preference",
|
||||
mixins: [baseFormMixin],
|
||||
components: {
|
||||
siteFooter,
|
||||
siteHeader,
|
||||
siteSubHeader,
|
||||
Form,
|
||||
},
|
||||
data() {
|
||||
return {};
|
||||
},
|
||||
async beforeRouteEnter(to, from, next) {
|
||||
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
|
||||
// Settle promises and get results
|
||||
const promiseResultMap = [
|
||||
{
|
||||
resultKey: "cmsContent",
|
||||
promise: cmsContentPromise,
|
||||
},
|
||||
];
|
||||
const resultMap = await settleAllPromises(promiseResultMap);
|
||||
next((vm) => {
|
||||
vm.setCmsContent(resultMap.cmsContent);
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
arePagePrerequisiteValid() {
|
||||
return true;
|
||||
},
|
||||
backButtonAction() {
|
||||
/**
|
||||
* this.navigationScenarios comes from base-mixin
|
||||
*/
|
||||
this.$router.navigate(this.navigationScenarios.CLICKED_BACK, this.$route);
|
||||
},
|
||||
async forwardButtonAction() {},
|
||||
resetDependentState() {},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
@ -18,6 +18,7 @@ export const issPageValues = {
|
|||
CAPABILITY_QUESTIONS: "capability-questions",
|
||||
COVERAGE_STATEMENT: "coverage-statement",
|
||||
PROVIDER_PREFERENCE: "provider-preference",
|
||||
SERVICE_LOCATION: "service-location",
|
||||
REVEAL: "reveal",
|
||||
ESTIMATE: "estimate",
|
||||
ADDRESS_VEHICLES: "address-vehicles",
|
||||
|
|
|
|||
|
|
@ -42,6 +42,8 @@ const navigationScenarios = {
|
|||
CLICKED_BACK_WITH_NO_VIN_NOR_QUESTIONS: "CLICKED_BACK_WITH_NO_VIN_NOR_QUESTIONS",
|
||||
|
||||
CLICKED_FORWARD_COVERAGE_STATEMENT: "CLICKED_FORWARD_COVERAGE_STATEMENT",
|
||||
|
||||
CLICKED_FORWARD_WITH_SAFELITE: "CLICKED_FORWARD_WITH_SAFELITE",
|
||||
};
|
||||
|
||||
export { navigationScenarios };
|
||||
|
|
@ -427,6 +427,19 @@ const routingTable = function(store) {
|
|||
],
|
||||
|
||||
},
|
||||
{
|
||||
issPageValue: issPageValues.PROVIDER_PREFERENCE,
|
||||
maps: [
|
||||
{
|
||||
scenario: navigationScenarios.CLICKED_BACK,
|
||||
destinationIssPageValue: issPageValues.COVERAGE_STATEMENT,
|
||||
},
|
||||
{
|
||||
scenario: navigationScenarios.CLICKED_FORWARD_WITH_SAFELITE,
|
||||
destinationIssPageValue: issPageValues.SERVICE_LOCATION,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
];
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue