Merge branch 'develop' into feature/Digital/SSR-241

This commit is contained in:
Jethe 2023-03-31 11:30:16 +05:30
commit cba68329d4
9 changed files with 309 additions and 13 deletions

View 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);
});
});

View file

@ -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() {},
},
};

View file

@ -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.",
};

View file

@ -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 {

View 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>

View file

@ -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",

View file

@ -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 };

View file

@ -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,
},
],
},
];
};

View file

@ -47,6 +47,7 @@ export default {
position: relative;
width: 1rem;
height: 1rem;
border-radius:50%;
animation: rotation 1s infinite linear;
@keyframes rotation {
100% {