Added logic to validate pages

This commit is contained in:
FrankRua 2022-01-27 17:23:09 -05:00
parent a05d77858e
commit 915cfd5a21
7 changed files with 157 additions and 62 deletions

View file

@ -1,11 +1,9 @@
<template>
<div class="container-fluid shadow rounded-3 p-0 position-relative">
<funnelHeader ref="funnelHeader" />
<vehicleBanner ref="vehicleBanner" />
<funnelSubHeader
ref="funnelSubHeader"
/>
</div>
<div class="container-fluid shadow rounded-3 p-0 position-relative">
<funnelHeader ref="funnelHeader" />
<vehicleBanner ref="vehicleBanner" />
<funnelSubHeader ref="funnelSubHeader" />
</div>
</template>
<script>
@ -20,24 +18,28 @@ import store from "@/store";
import baseMixin from "@/mixins/base-mixin";
import { storeActions } from "@/constants/store-actions";
export default ({
name: "vehicle-damage",
async beforeRouteEnter(to, from, next) {
// Call APIs
const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage);
const damageOptionsPromise = baseMixin.methods.dispatchNonBlockingStoreAction(storeActions.GET_DAMAGE_OPTIONS, {carId: store.getters.vehicle.carId});
export default {
name: "vehicle-damage",
async beforeRouteEnter(to, from, next) {
// Call APIs
const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage);
const damageOptionsPromise =
baseMixin.methods.dispatchNonBlockingStoreAction(
storeActions.GET_DAMAGE_OPTIONS,
{ carId: store.getters.vehicle.carId }
);
// Settle promises and get results
const promiseResultMap = [
{
resultKey: "cmsContent",
promise: cmsContentPromise,
},
{
resultKey: "damageOptions",
promise: damageOptionsPromise
},
];
// Settle promises and get results
const promiseResultMap = [
{
resultKey: "cmsContent",
promise: cmsContentPromise,
},
{
resultKey: "damageOptions",
promise: damageOptionsPromise,
},
];
const resultMap = await settleAllPromises(promiseResultMap);
@ -54,12 +56,16 @@ export default ({
);
// use resultMap.damageOptions for damage options
});
},
methods: {
arePagePrerequisitesValid() {
return store.getters.vehicle.carId !== null;
},
},
components: {
funnelHeader,
vehicleBanner,
funnelSubHeader,
},
});
};
</script>

View file

@ -7,23 +7,40 @@ import vehicleBanner from "@/common-components/vehicle-banner/vehicle-banner";
import funnelSubHeader from "@/common-components/funnel-sub-header/funnel-sub-header";
import { settleAllPromises } from "@/helpers/layout-helper.js";
import { nextTick } from "vue";
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
// Mock Store
jest.mock("@/store", () => ({
getters: {
vehicle: {
year: 2019,
}
}
}));
// Mock fetchCmsContentForPage
jest.mock("@/helpers/cms-content-helper", () => ({
fetchCmsContentForPage: jest.fn(),
}));
// Mock our module for promises.
jest.mock("@/helpers/layout-helper.js", () => ({
settleAllPromises: jest.fn(),
}));
describe("vehicle-make.vue", () => {
test("Make question component is initized with api data", async (done) => {
//Arrange
const vehicleMakeQuestionCmsContent = { QuestionText: "What make is your vehicle?" };
const makeQuestionInitialData = ["honda", "ford", "dodge"];
const { wrapper, apiPromise } = setupMocks( {
vehicleMakeQuestionCmsContent: vehicleMakeQuestionCmsContent,
const { wrapper, apiPromise } = setupMocks({
vehicleMakeQuestionCmsContent: vehicleMakeQuestionCmsContent,
makeQuestionInitialData: makeQuestionInitialData,
} );
});
//Act
vehicleMake.beforeRouteEnter.call(wrapper.vm, { query: { fmgPage: "vehicle-make" } }, undefined, (c) => c(wrapper.vm));
@ -40,8 +57,8 @@ describe("vehicle-make.vue", () => {
//Arrange
const pageHeaderWidgetHeaderText = "Select a make to get started";
const { wrapper, apiPromise } = setupMocks( { pageHeaderWidgetHeaderText: pageHeaderWidgetHeaderText });
const { wrapper, apiPromise } = setupMocks({ pageHeaderWidgetHeaderText: pageHeaderWidgetHeaderText });
//Act
vehicleMake.beforeRouteEnter.call(wrapper.vm, { query: { fmgPage: "vehicle-make" } }, undefined, (c) => c(wrapper.vm));
@ -61,8 +78,8 @@ describe("vehicle-make.vue", () => {
LogoImage:
"https://digitalconsumercms-dev.safelite.com/images/default-source/default-album/safelite-logo.svg?sfvrsn=45e7ed06_3",
}
const { wrapper, apiPromise } = setupMocks( { SiteHeaderWidget: SiteHeaderWidget});
const { wrapper, apiPromise } = setupMocks({ SiteHeaderWidget: SiteHeaderWidget });
//Act
vehicleMake.beforeRouteEnter.call(wrapper.vm, { query: { fmgPage: "vehicle-make" } }, undefined, (c) => c(wrapper.vm));
@ -82,8 +99,8 @@ describe("vehicle-make.vue", () => {
GenericVehicleImage:
"https://digitalconsumercms-dev.safelite.com/images/default-source/default-album/blurred-image.jpg?sfvrsn=a6ce3034_3",
}
const { wrapper, apiPromise } = setupMocks( { VehicleBannerWidget: VehicleBannerWidget});
const { wrapper, apiPromise } = setupMocks({ VehicleBannerWidget: VehicleBannerWidget });
//Act
vehicleMake.beforeRouteEnter.call(wrapper.vm, { query: { fmgPage: "vehicle-make" } }, undefined, (c) => c(wrapper.vm));
@ -97,9 +114,9 @@ describe("vehicle-make.vue", () => {
describe("vehicle-make.vue", () => {
test("BackButtonAction triggers a router.navigate change", async (done) => {
//Arrange
const { wrapper, apiPromise } = setupMocks( {
const { wrapper, apiPromise } = setupMocks({
pageHeaderWidgetHeaderText: "Select a make to get started",
mountOptionsMockData: {
router: {
@ -121,32 +138,59 @@ describe("vehicle-make.vue", () => {
});
});
describe("vehicle-make.vue", () => {
test("arePagePrerequisitesValid", async (done) => {
//Arrange
const { wrapper, apiPromise } = setupMocks({
pageHeaderWidgetHeaderText: "Select a make to get started",
mountOptionsMockData: {},
});
//Act
vehicleMake.beforeRouteEnter.call(wrapper.vm, { query: { fmgPage: "vehicle-make" } }, undefined, (c) => c(wrapper.vm));
let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid();
await nextTick();
//Assert
apiPromise.finally(() => {
expect(arePagePrerequisitesValid).toBe(true);
done();
});
});
});
function setupMocks({
vehicleMakeQuestionCmsContent = {},
makeQuestionInitialData = {},
pageHeaderWidgetHeaderText = {},
mountOptionsMockData = {},
}) {
//Mock api responses
const apiResponses = {
cmsContent: {
FunnelSubHeaderWidget: pageHeaderWidgetHeaderText,
VehicleMakeQuestion: vehicleMakeQuestionCmsContent,
VehicleBannerWidget:
{
GenericVehicleImage:
"https://digitalconsumercms-dev.safelite.com/images/default-source/default-album/blurred-image.jpg?sfvrsn=a6ce3034_3",
},
FunnelHeaderWidget:
{
LogoImage:
"https://digitalconsumercms-dev.safelite.com/images/default-source/default-album/safelite-logo.svg?sfvrsn=45e7ed06_3",
},
VehicleBannerWidget:
{
GenericVehicleImage:
"https://digitalconsumercms-dev.safelite.com/images/default-source/default-album/blurred-image.jpg?sfvrsn=a6ce3034_3",
},
FunnelHeaderWidget:
{
LogoImage:
"https://digitalconsumercms-dev.safelite.com/images/default-source/default-album/safelite-logo.svg?sfvrsn=45e7ed06_3",
},
},
makeQuestionInitialData: makeQuestionInitialData,
};
const apiPromise = Promise.resolve(apiResponses);
fetchCmsContentForPage.mockImplementation(() => Promise.resolve());
settleAllPromises.mockImplementation(() => apiPromise);
//Mock make question methods
@ -163,6 +207,7 @@ function setupMocks({
funnelSubHeader.methods = {
initializeComponent: jest.fn(),
};
const mountOptions = getMountOptions(mountOptionsMockData);
const wrapper = shallowMount(vehicleMake, mountOptions);
const makeQuestionWrapper = wrapper.findComponent({ name: "makeQuestion" });

View file

@ -4,11 +4,11 @@
<div class="select-car">
<div class="select-car-form rounded text-center">
<vehicleBanner ref="vehicleBanner" />
<funnelSubHeader
ref="funnelSubHeader"
:hasBackButton="true"
backButtonAccessibleText="Change Vehicle Year"
@click-event="backButtonAction"
<funnelSubHeader
ref="funnelSubHeader"
:hasBackButton="true"
backButtonAccessibleText="Change Vehicle Year"
@click-event="backButtonAction"
/>
<makeQuestion v-model="selectedMake" ref="makeQuestion" />
</div>
@ -25,6 +25,7 @@ import funnelSubHeader from "@/common-components/funnel-sub-header/funnel-sub-he
// Supporting files
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
import { settleAllPromises } from "@/helpers/layout-helper";
import store from "@/store";
export default {
name: "vehicle-make",
data() {
@ -53,7 +54,6 @@ export default {
];
const resultMap = await settleAllPromises(promiseResultMap);
// Call the "next" function to complete the transition to this page.
next((vm) => {
vm.$refs.funnelSubHeader.initializeComponent(
@ -77,6 +77,10 @@ export default {
// route to move backwards
this.$router.navigate(this.navigationScenarios.CLICKED_BACK, this.$route);
},
arePagePrerequisitesValid() {
console.log(store.getters.vehicle);
return store.getters.vehicle.year !== null;
},
},
watch: {

View file

@ -25,6 +25,8 @@ import vehicleBanner from "@/common-components/vehicle-banner/vehicle-banner";
// Supporting files
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
import { settleAllPromises } from "@/helpers/layout-helper";
import store from "@/store";
export default {
name: "vehicle-model",
data() {
@ -77,6 +79,9 @@ export default {
// route to move backwards
this.$router.navigate(this.navigationScenarios.CLICKED_BACK, this.$route);
},
arePagePrerequisitesValid() {
return store.getters.vehicle.make !== null;
},
},
watch: {

View file

@ -25,6 +25,8 @@ import vehicleBanner from "@/common-components/vehicle-banner/vehicle-banner";
// Supporting files
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
import { settleAllPromises } from "@/helpers/layout-helper";
import store from "@/store";
export default {
name: "vehicle-style",
data() {
@ -78,17 +80,31 @@ export default {
this.$router.navigate(this.navigationScenarios.CLICKED_BACK, this.$route);
},
setVehicle() {
return this.dispatchNonBlockingStoreAction(this.storeActions.SET_VEHICLE, {year: this.$store.getters.vehicle.year, make: this.$store.getters.vehicle.make, model: this.$store.getters.vehicle.model, style: this.$store.getters.vehicle.style});
}
return this.dispatchNonBlockingStoreAction(
this.storeActions.SET_VEHICLE,
{
year: this.$store.getters.vehicle.year,
make: this.$store.getters.vehicle.make,
model: this.$store.getters.vehicle.model,
style: this.$store.getters.vehicle.style,
}
);
},
arePagePrerequisitesValid() {
return store.getters.vehicle.model !== null;
},
},
watch: {
selectedStyle(style) {
this.$store.commit(this.storeMutations.UPDATE_STYLE, style);
this.setVehicle().then(() => {
this.$router.navigate(this.navigationScenarios.SELECTED_STYLE, this.$route);
this.$router.navigate(
this.navigationScenarios.SELECTED_STYLE,
this.$route
);
});
}
},
},
components: {

View file

@ -4,9 +4,7 @@
<div class="select-car">
<div class="select-car-form rounded text-center">
<vehicleBanner ref="vehicleBanner" />
<funnelSubHeader
ref="funnelSubHeader"
/>
<funnelSubHeader ref="funnelSubHeader" />
<yearQuestion v-model="selectedYear" ref="yearQuestion" />
</div>
</div>
@ -80,6 +78,11 @@ export default {
);
},
},
methods: {
arePagePrerequisitesValid() {
return true;
},
},
components: {
yearQuestion,
funnelHeader,

View file

@ -44,6 +44,13 @@ const routes = [
try {
// If we already have our route, go to it.
if (router.hasRoute(to.query.fmgPage)) {
// Since our route is already in scope, we can grab the component from it and call the arePagePrerequisitesValid function.
let arePagePrerequisitesValid = router.getRoutes().filter(x => x.name === to.query.fmgPage)[0].components.default.methods.arePagePrerequisitesValid();
if (!arePagePrerequisitesValid) {
await GoToFunnelStartOn404(next);
}
return next({ name: to.query.fmgPage, query: to.query });
}
@ -57,9 +64,17 @@ const routes = [
component: routeData[0].component,
});
// Call the next components arePagePrerequisitesValid method before load.
// If it returns false, use the 404 logic.
let nextComponent = await router.getRoutes().filter(x => x.name === routeData[0].name)[0].components.default();
if (!nextComponent.default.methods.arePagePrerequisitesValid()) {
await GoToFunnelStartOn404(next);
}
// Assign current query string parameters, as well as our fmgPage one.
next({ name: routeData[0].name, query: Object.assign(to.query, { fmgPage: routeData[0].name }) });
} catch (error) {
console.log(error);
@ -79,6 +94,7 @@ const router = createRouter({
//---------------------------------------------------------- Router Functions ----------------------------------------------------------
// Navigate to the next route, depending on the scenario.
router.navigate = (
scenario,