Added logic to validate pages
This commit is contained in:
parent
a05d77858e
commit
915cfd5a21
7 changed files with 157 additions and 62 deletions
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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" });
|
||||
|
|
|
|||
|
|
@ -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: {
|
||||
|
|
|
|||
|
|
@ -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: {
|
||||
|
|
|
|||
|
|
@ -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: {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
Loading…
Reference in a new issue