Merge branch 'develop' into feature/digital/SSR-480

This commit is contained in:
Katie Kroell 2023-05-30 15:47:53 -04:00
commit d36532c0b2
18 changed files with 11 additions and 1571 deletions

View file

@ -20,6 +20,7 @@
type="button"
class="btn-close"
@mousedown="closeModal"
@keypress.space="closeModal"
aria-label="Close"></button>
</div>
<div class="modal-body ps-5 pe-5 pb-4 pt-0">

View file

@ -16,7 +16,7 @@
class="form-control"
v-model.trim="value"
v-maska="mask"
v-on:focus="blurInput"
@keydown="preventDateInput"
:type="type"
:ref="inputId"
:id="inputId"
@ -139,11 +139,15 @@ export default {
},
blurInput() {
if (this.$refs.dateOfLossField) {
this.$refs.dateOfLossField.blur();
}
}
preventDateInput(evt) {
if (this.type === "date") {
if (/\d/.test(evt.key)) {
evt.stopPropagation();
evt.preventDefault();
return false;
}
}
}
},
computed: {

View file

@ -1,70 +0,0 @@
import makeQuestion from "@/layouts/vehicle-make/make-question/make-question";
import { shallowMount } from "@vue/test-utils";
import { getMountOptions } from "@/helpers/unit-test-helper.js";
import { useMainStore } from "@/store";
describe("make-question.vue", () => {
test("Data from store api are used as radio question answers.", async () => {
//Arrange
const { wrapper, cmsContent } = setupMocks({
dataFromStoreApi: ["honda", "ford", "dodge"],
});
//Act
const initialData = makeQuestion.methods.loadInitialData.call(wrapper.vm);
makeQuestion.methods.initializeComponent.call(
wrapper.vm,
initialData
);
//Assert
const buttonQuestionComponent = await wrapper.findComponent({
name: "buttonQuestion",
});
expect(buttonQuestionComponent.attributes("answers")).toBe(
"honda,ford,dodge"
);
});
test("Selected make is emitted upon selection.", async () => {
//Arrange
const { wrapper } = setupMocks({ modelValueProp: "honda" });
const makeToSelect = "ford";
//Act
wrapper.setValue({ selectedMake: makeToSelect });
await wrapper.vm.$nextTick();
//Assert
expect(wrapper.emitted()["update:modelValue"][0]).toEqual([
{ selectedMake: "ford" },
]);
});
});
function setupMocks({
modelValueProp = "1900",
cmsQuestionText = "CMS text goes here",
dataFromStoreApi = [],
}) {
//Mock store
const mountOptions = getMountOptions();
const store = useMainStore();
store.getVehicleMakes = jest.fn(() => dataFromStoreApi);
mountOptions.propsData = {
modelValue: modelValueProp,
};
const wrapper = shallowMount(makeQuestion, mountOptions);
//Mock CMS content
const cmsContent = {
QuestionText: cmsQuestionText,
};
return { wrapper, cmsContent };
}

View file

@ -1,56 +0,0 @@
<template>
<buttonQuestion
class="radioQuestion"
isOverflowScrollable
selectingInitiatesLoad
:questionText="questionText"
:answers="makes"
groupName="ChooseVehicleMake"
textPosition="text-start"
v-model="selectedValue"
isRequired
/>
</template>
<script>
import buttonQuestion from "@/digital-components/button-question/button-question";
import { useMainStore } from '@/store';
export default {
name: "make-question",
data() {
return {
makes: [],
};
},
props: {
modelValue: String,
cmsWidgetName: String,
},
components: {
buttonQuestion,
},
computed: {
questionText(){
return this.getCmsContent(this.cmsWidgetName, 'QuestionText');
},
selectedValue: {
get: function() {
return this.modelValue
},
set: function(newValue) {
this.$emit("update:modelValue", newValue);
}
}
},
methods: {
loadInitialData() {
return useMainStore().getVehicleMakes();
},
initializeComponent(initialData) {
this.makes = initialData;
},
},
};
</script>

View file

@ -1,154 +0,0 @@
// Supporting Files
import { shallowMount } from "@vue/test-utils";
import { settleAllPromises } from "@/helpers/layout-helper.js";
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
import baseMixin from "@/mixins/base-mixin.js";
import { getMountOptions } from "@/helpers/unit-test-helper.js";
import { nextTick } from "vue";
import { useMainStore } from "@/store";
import { applicationConfig } from "@/constants/application-config";
// Components
import vehicleMake from "@/layouts/vehicle-make/vehicle-make.vue";
import makeQuestion from "@/layouts/vehicle-make/make-question/make-question";
// 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 () => {
//Arrange
const makeQuestionInitialData = ["honda", "ford", "dodge"];
const { wrapper, apiPromise } = setupMocks({
makeQuestionInitialData: makeQuestionInitialData,
});
//Act
vehicleMake.beforeRouteEnter.call(
wrapper.vm,
{ query: { issPage: "vehicle-make" } },
undefined,
(c) => c(wrapper.vm)
);
//Assert
return apiPromise.finally(() => {
try {
expect(makeQuestion.methods.initializeComponent).toHaveBeenCalledWith(
makeQuestionInitialData
);
}
catch (e) {
throw e
}
});
});
test("BackButtonAction triggers a router.navigate change", async () => {
//Arrange
const { wrapper, apiPromise } = setupMocks({
pageHeaderWidgetHeaderText: "Select a make to get started",
mountOptionsMockData: {
router: {
navigate: jest.fn(),
},
},
});
//Act
vehicleMake.beforeRouteEnter.call(
wrapper.vm,
{ query: { issPage: "vehicle-make" } },
undefined,
(c) => c(wrapper.vm)
);
wrapper.vm.backButtonAction();
await nextTick();
//Assert
return apiPromise.finally(() => {
try {
expect(wrapper.vm.$router.navigate).toHaveBeenCalled();
}
catch (e) {
throw e
}
});
});
test("Year set, arePagePrerequisitesValid should be true ", () => {
//Arrange
const { wrapper } = setupMocks({});
useMainStore().order.vehicle.year = 2001;
//Act
vehicleMake.beforeRouteEnter.call(
wrapper.vm,
{ query: { issPage: "vehicle-make" } },
undefined,
(c) => c(wrapper.vm)
);
let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid();
//Assert
expect(arePagePrerequisitesValid).toBe(true);
});
});
function setupMocks({
vehicleMakeQuestionCmsContent = {},
makeQuestionInitialData = {},
pageHeaderWidgetHeaderText = {},
mountOptionsMockData = {},
}) {
//Mock api responses
const apiResponses = {
cmsContent: {
SiteSubHeaderWidget: pageHeaderWidgetHeaderText,
VehicleMakeQuestion: vehicleMakeQuestionCmsContent,
VehicleBannerWidget: {
GenericVehicleImage:
`${applicationConfig.ISS_DEV_CMS_DOMAIN}/images/default-source/default-album/blurred-image.jpg`,
},
SiteHeaderWidget: {
LogoImage:
`${applicationConfig.ISS_DEV_CMS_DOMAIN}/images/default-source/default-album/logos/insuranceLogo.jpg`,
},
},
makeQuestionInitialData: makeQuestionInitialData,
};
const apiPromise = Promise.resolve(apiResponses);
settleAllPromises.mockImplementation(() => apiPromise);
fetchCmsContentForPage.mockImplementation(() => Promise.resolve());
//Mock make question methods
makeQuestion.methods = {
loadInitialData: jest.fn(),
initializeComponent: jest.fn(),
};
const mountOptions = getMountOptions(mountOptionsMockData);
const wrapper = shallowMount(vehicleMake, mountOptions);
const makeQuestionWrapper = wrapper.findComponent({ name: "makeQuestion" });
makeQuestionWrapper.vm.initializeComponent =
makeQuestion.methods.initializeComponent;
wrapper.vm.setCmsContent = baseMixin.methods.setCmsContent;
return { wrapper, apiPromise };
}

View file

@ -1,102 +0,0 @@
<template>
<div class="page-container-grouped-styles position-relative">
<div class="fade-on-route-transition position-relative">
<siteHeader cmsWidgetName="SiteHeaderWidget" />
<div class="select-car">
<div class="container-fluid pb-2 px-5">
<div class="row">
<div class="col">
<div class="select-car-form rounded text-center">
<vehicleBanner cmsWidgetName="VehicleBannerWidget" :displayGenericVehicleImage="true" class="mb-3" />
<siteSubHeader cmsWidgetName="SiteSubHeaderWidget" :hasBackButton="true" @click-event="backButtonAction" />
<makeQuestion v-model="selectedMake" ref="makeQuestion" cmsWidgetName="VehicleMakeQuestion" />
<siteFooter cmsWidgetName="SiteFooterWidget" ref="siteFooter" @back-clicked="backButtonAction" :isForwardButtonHidden="shouldHideForwardButton" />
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
// Components
import makeQuestion from "@/layouts/vehicle-make/make-question/make-question";
import siteHeader from "@/iss-components/site-header/site-header";
import siteSubHeader from "@/iss-components/site-sub-header/site-sub-header";
import vehicleBanner from "@/iss-components/vehicle-banner/vehicle-banner";
import siteFooter from "@/iss-components/site-footer/site-footer";
// Supporting files
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
import { settleAllPromises } from "@/helpers/layout-helper";
export default {
name: 'vehicle-make',
data() {
return {
selectedMake: null,
shouldHideForwardButton: true
};
},
async beforeRouteEnter(to, from, next) {
// Call APIs
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
const makeQuestionInitialDataPromise = makeQuestion.methods.loadInitialData();
// Settle promises and get results
const promiseResultMap = [
{
resultKey: "cmsContent",
promise: cmsContentPromise,
},
{
resultKey: "makeQuestionInitialData",
promise: makeQuestionInitialDataPromise,
},
];
let resultMap = await settleAllPromises(promiseResultMap);
// Call the "next" function to complete the transition to this page.
next((vm) => {
vm.setCmsContent(resultMap.cmsContent);
vm.$refs.makeQuestion.initializeComponent(
resultMap.makeQuestionInitialData
);
});
},
methods: {
backButtonAction() {
this.$router.navigate(
this.navigationScenarios.CLICKED_BACK,
this.$route
);
},
arePagePrerequisitesValid() {
if (this.mainStore.order.vehicle.year){
return true;
}
return false;
},
},
components: {
makeQuestion,
siteHeader,
siteSubHeader,
vehicleBanner,
siteFooter
},
watch: {
selectedMake(make) {
this.mainStore.updateVehicleMake( make );
this.$router.navigate(
this.navigationScenarios.SELECTED_MAKE,
this.$route
);
},
}
};
</script>

View file

@ -1,71 +0,0 @@
import modelQuestion from "@/layouts/vehicle-model/model-question/model-question";
import { shallowMount } from "@vue/test-utils";
import { getMountOptions } from "@/helpers/unit-test-helper.js";
import { useMainStore } from "@/store";
describe("model-question.vue", () => {
test("Selected model is emitted upon selection.", async () => {
//Arrange
const { wrapper } = setupMocks({ modelValueProp: "Accord" });
const modelToSelect = "Civic";
//Act
wrapper.setValue({ selectedModel: modelToSelect });
await wrapper.vm.$nextTick();
//Assert
expect(wrapper.emitted()["update:modelValue"][0]).toEqual([
{ selectedModel: "Civic" },
]);
});
});
describe("model-question.vue", () => {
test("Data from store api are used as radio question answers.", async () => {
//Arrange
const { wrapper, cmsContent } = setupMocks({
dataFromStoreApi: ["accord", "civic", "insight"],
});
//Act
const initialData = modelQuestion.methods.loadInitialData.call(wrapper.vm);
modelQuestion.methods.initializeComponent.call(
wrapper.vm,
initialData
);
//Assert
const buttonQuestionComponent = await wrapper.findComponent({
name: "buttonQuestion",
});
expect(buttonQuestionComponent.attributes("answers")).toBe(
"accord,civic,insight"
);
});
});
function setupMocks({
modelValueProp = "1900",
cmsQuestionText = "CMS text goes here",
dataFromStoreApi = [],
}) {
//Mock store
const store = useMainStore();
store.getVehicleModels = jest.fn(() => dataFromStoreApi);
const mountOptions = getMountOptions();
//Mock props
mountOptions.propsData = {
modelValue: modelValueProp,
};
const wrapper = shallowMount(modelQuestion, mountOptions);
//Mock CMS content
const cmsContent = {
QuestionText: cmsQuestionText,
};
return { wrapper, cmsContent };
}

View file

@ -1,56 +0,0 @@
<template>
<buttonQuestion
class="radioQuestion"
isOverflowScrollable
selectingInitiatesLoad
:questionText="questionText"
:answers="models"
groupName="ChooseVehicleModel"
textPosition="text-start"
v-model="selectedValue"
isRequired
/>
</template>
<script>
import buttonQuestion from "@/digital-components/button-question/button-question";
import { useMainStore } from '@/store';
export default {
name: "model-question",
data() {
return {
models: Array,
};
},
props: {
modelValue: String,
cmsWidgetName: String,
},
computed: {
questionText(){
return this.getCmsContent(this.cmsWidgetName, 'QuestionText');
},
selectedValue: {
get: function() {
return this.modelValue
},
set: function(newValue) {
this.$emit("update:modelValue", newValue);
}
}
},
components: {
buttonQuestion,
},
methods: {
loadInitialData() {
return useMainStore().getVehicleModels();
},
initializeComponent(initialData) {
this.models = initialData;
},
},
};
</script>

View file

@ -1,152 +0,0 @@
// Components
import vehicleModel from "@/layouts/vehicle-model/vehicle-model.vue";
import modelQuestion from "@/layouts/vehicle-model/model-question/model-question";
// Supporting files
import { shallowMount } from "@vue/test-utils";
import { settleAllPromises } from "@/helpers/layout-helper.js";
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
import baseMixin from "@/mixins/base-mixin.js";
import { getMountOptions } from "@/helpers/unit-test-helper.js";
import { nextTick } from "vue";
import { useMainStore } from "@/store";
import { applicationConfig } from "@/constants/application-config";
// Mock our module for promises.
jest.mock("@/helpers/layout-helper.js", () => ({
settleAllPromises: jest.fn(),
}));
// Mock fetchCmsContentForPage
jest.mock("@/helpers/cms-content-helper", () => ({
fetchCmsContentForPage: jest.fn(),
}));
describe("vehicle-model.vue", () => {
test("Model question component is initized with api data", async () => {
//Arange
const modelQuestionInitialData = ["accord", "civic", "insight"];
const { wrapper, apiPromise } = setupMocks({
modelQuestionInitialData: modelQuestionInitialData,
});
//Act
vehicleModel.beforeRouteEnter.call(
wrapper.vm,
{ query: { issPage: "vehicle-model" } },
undefined,
(c) => c(wrapper.vm)
);
//Assert
return apiPromise.finally(() => {
try {
expect(modelQuestion.methods.initializeComponent).toHaveBeenCalledWith(
modelQuestionInitialData
);
}
catch (e) {
throw e
}
});
});
});
describe("vehicle-model.vue", () => {
test("BackButtonAction triggers a router.navigate change", async () => {
//Arrange
const { wrapper, apiPromise } = setupMocks({
pageHeaderWidgetHeaderText: "Select a model to get started",
mountOptionsMockData: {
router: {
navigate: jest.fn(),
},
},
});
//Act
vehicleModel.beforeRouteEnter.call(
wrapper.vm,
{ query: { issPage: "vehicle-model" } },
undefined,
(c) => c(wrapper.vm)
);
wrapper.vm.backButtonAction();
await nextTick();
//Assert
return apiPromise.finally(() => {
try {
expect(wrapper.vm.$router.navigate).toHaveBeenCalled();
}
catch (e) {
throw e
}
});
});
});
describe("vehicle-model.vue", () => {
test("Make set, arePagePrerequisitesValid should be true ", () => {
//Arrange
const { wrapper } = setupMocks({});
useMainStore().order.vehicle.make = "Honda";
//Act
vehicleModel.beforeRouteEnter.call(
wrapper.vm,
{ query: { issPage: "vehicle-model" } },
undefined,
(c) => c(wrapper.vm)
);
let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid();
//Assert
expect(arePagePrerequisitesValid).toBe(true);
});
});
function setupMocks({
buttonQuestionContent = {},
modelQuestionInitialData = {},
pageHeaderWidgetHeaderText = {},
mountOptionsMockData = {},
}) {
//Mock api responses
const apiResponses = {
cmsContent: {
SiteSubHeaderWidget: pageHeaderWidgetHeaderText,
VehicleModelQuestion: buttonQuestionContent,
VehicleBannerWidget: {
GenericVehicleImage:
`${applicationConfig.ISS_DEV_CMS_DOMAIN}/images/default-source/default-album/blurred-image.jpg`,
},
SiteHeaderWidget: {
LogoImage:
`${applicationConfig.ISS_DEV_CMS_DOMAIN}/images/default-source/default-album/logos/insuranceLogo.jpg`,
},
},
modelQuestionInitialData: modelQuestionInitialData,
};
const apiPromise = Promise.resolve(apiResponses);
settleAllPromises.mockImplementation(() => apiPromise);
fetchCmsContentForPage.mockImplementation(() => Promise.resolve());
//Mock model question methods
modelQuestion.methods = {
loadInitialData: jest.fn(),
initializeComponent: jest.fn(),
};
const mountOptions = getMountOptions(mountOptionsMockData);
const wrapper = shallowMount(vehicleModel, mountOptions);
wrapper.vm.setCmsContent = baseMixin.methods.setCmsContent;
const modelQuestionWrapper = wrapper.findComponent({ name: "modelQuestion" });
modelQuestionWrapper.vm.initializeComponent =
modelQuestion.methods.initializeComponent;
return { wrapper, apiPromise };
}

View file

@ -1,111 +0,0 @@
<template>
<div class="page-container-grouped-styles position-relative">
<div class="fade-on-route-transition position-relative">
<siteHeader cmsWidgetName="SiteHeaderWidget" />
<div class="select-car">
<div class="container-fluid pb-2 px-5">
<div class="row">
<div class="col">
<div class="select-car-form rounded text-center">
<vehicleBanner cmsWidgetName="VehicleBannerWidget" :displayGenericVehicleImage="true" class="mb-3" />
<siteSubHeader cmsWidgetName="SiteSubHeaderWidget" :hasBackButton="true" :backButtonAccessibleText="backButtonAccessibleText" @click-event="backButtonAction" />
<modelQuestion v-model="selectedModel" ref="modelQuestion" cmsWidgetName="VehicleModelQuestion" />
<siteFooter cmsWidgetName="SiteFooterWidget" ref="siteFooter" @back-clicked="backButtonAction" :isForwardButtonHidden="shouldHideForwardButton" />
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
// Components
import modelQuestion from "@/layouts/vehicle-model/model-question/model-question";
import siteHeader from "@/iss-components/site-header/site-header";
import siteSubHeader from "@/iss-components/site-sub-header/site-sub-header";
import vehicleBanner from "@/iss-components/vehicle-banner/vehicle-banner";
import siteFooter from "@/iss-components/site-footer/site-footer";
// Supporting files
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
import { settleAllPromises } from "@/helpers/layout-helper";
export default {
name: "vehicle-model",
data() {
return {
selectedModel: null,
shouldHideForwardButton: true
};
},
async beforeRouteEnter(to, from, next) {
// Call APIs
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
const modelQuestionInitialDataPromise =
modelQuestion.methods.loadInitialData();
// Settle promises and get results
const promiseResultMap = [
{
resultKey: "cmsContent",
promise: cmsContentPromise,
},
{
resultKey: "modelQuestionInitialData",
promise: modelQuestionInitialDataPromise,
},
];
const resultMap = await settleAllPromises(promiseResultMap);
// Call the "next" function to complete the transition to this page.
next((vm) => {
vm.setCmsContent(resultMap.cmsContent);
vm.$refs.modelQuestion.initializeComponent(
resultMap.modelQuestionInitialData
);
});
},
methods: {
backButtonAction() {
// route to move backwards
this.$router.navigate(
this.navigationScenarios.CLICKED_BACK,
this.$route
);
},
arePagePrerequisitesValid()
{
if(this.mainStore.order.vehicle.make){
return true;
}
return false;
},
},
computed: {
backButtonAccessibleText()
{
return this.getCmsContent(this.cmsWidgetName, "BackButtonAccessibleText")
}
},
watch: {
selectedModel(model) {
this.mainStore.updateVehicleModel( model );
this.$router.navigate(
this.navigationScenarios.SELECTED_MODEL,
this.$route
);
},
},
components: {
modelQuestion,
siteHeader,
siteSubHeader,
vehicleBanner,
siteFooter
},
};
</script>

View file

@ -1,62 +0,0 @@
import styleQuestion from "@/layouts/vehicle-style/style-question/style-question";
import { shallowMount } from "@vue/test-utils";
import { getMountOptions } from "@/helpers/unit-test-helper.js";
import { useMainStore } from "@/store";
describe("style-question.vue", () => {
test("Data from store api are used as radio question answers.", async () => {
//Arrange
const { wrapper, cmsContent } = setupMocks({
dataFromStoreApi: ["2 Door", "4 Door"],
});
//Act
const initialData = styleQuestion.methods.loadInitialData.call(wrapper.vm);
styleQuestion.methods.initializeComponent.call(wrapper.vm, initialData);
//Assert
const buttonQuestionComponent = await wrapper.findComponent({
name: "buttonQuestion",
});
expect(buttonQuestionComponent.attributes("answers")).toBe("2 Door,4 Door");
});
test("Selected style is emitted upon selection.", async () => {
//Arrange
const { wrapper } = setupMocks({ modelValueProp: "2 Door" });
const styleToSelect = "4 Door";
//Act
wrapper.setValue({ selectedStyle: styleToSelect });
await wrapper.vm.$nextTick();
//Assert
expect(wrapper.emitted()["update:modelValue"][0]).toEqual([{ selectedStyle: "4 Door" }]);
});
});
function setupMocks({
modelValueProp = "1900",
cmsQuestionText = "CMS text goes here",
dataFromStoreApi = [],
}) {
//Mock store
const mountOptions = getMountOptions();
const store = useMainStore();
store.getVehicleStyles = jest.fn(() => dataFromStoreApi);
mountOptions.propsData = {
modelValue: modelValueProp,
};
const wrapper = shallowMount(styleQuestion, mountOptions);
//Mock CMS content
const cmsContent = {
QuestionText: cmsQuestionText,
};
return { wrapper, cmsContent };
}

View file

@ -1,54 +0,0 @@
<template>
<buttonQuestion
class="radioQuestion"
isOverflowScrollable
selectingInitiatesLoad
:questionText="questionText"
:answers="styles"
groupName="ChooseVehicleStyle"
textPosition="text-start"
v-model="selectedValue"
isRequired />
</template>
<script>
import buttonQuestion from "@/digital-components/button-question/button-question";
import { useMainStore } from '@/store';
export default {
name: "style-question",
data() {
return {
styles: [],
};
},
props: {
modelValue: String,
cmsWidgetName: String,
},
computed: {
questionText() {
return this.getCmsContent(this.cmsWidgetName, "QuestionText");
},
selectedValue: {
get: function () {
return this.modelValue;
},
set: function (newValue) {
this.$emit("update:modelValue", newValue);
},
},
},
components: {
buttonQuestion,
},
methods: {
loadInitialData() {
return useMainStore().getVehicleStyles();
},
initializeComponent(initialData) {
this.styles = initialData;
},
},
};
</script>

View file

@ -1,211 +0,0 @@
// Supporting files
import { shallowMount } from "@vue/test-utils";
import { settleAllPromises } from "@/helpers/layout-helper.js";
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
import baseMixin from "@/mixins/base-mixin.js";
import { getMountOptions } from "@/helpers/unit-test-helper.js";
import { nextTick } from "vue";
import { useMainStore } from "@/store";
import router from "@/router";
import { applicationConfig } from "@/constants/application-config";
// Components
import vehicleStyle from "@/layouts/vehicle-style/vehicle-style.vue";
import styleQuestion from "@/layouts/vehicle-style/style-question/style-question";
jest.mock("@/router", () => ({
overrideNavigation: jest.fn(),
}));
// Mock our module for promises.
jest.mock("@/helpers/layout-helper.js", () => ({
settleAllPromises: jest.fn(),
}));
// Mock fetchCmsContentForPage
jest.mock("@/helpers/cms-content-helper", () => ({
fetchCmsContentForPage: jest.fn(),
}));
describe("vehicle-style.vue", () => {
test("Style question component is initized with api data", async () => {
//Arrange
const styleQuestionInitialData = ["2 Door", "4 Door"];
const { wrapper, apiPromise } = setupMocks({
styleQuestionInitialData: styleQuestionInitialData,
});
//Act
vehicleStyle.beforeRouteEnter.call(
wrapper.vm,
{ query: { issPage: "vehicle-style" } },
undefined,
(c) => c(wrapper.vm)
);
//Assert
return apiPromise.finally(() => {
try {
expect(styleQuestion.methods.initializeComponent).toHaveBeenCalledWith(
styleQuestionInitialData
);
}
catch (e) {
throw e
}
});
});
test("BackButtonAction triggers a router.navigate change", async () => {
//Arrange
const { wrapper, apiPromise } = setupMocks({
pageHeaderWidgetHeaderText: "Select a style to get started",
mountOptionsMockData: {
router: {
navigate: jest.fn(),
},
},
});
//Act
vehicleStyle.beforeRouteEnter.call(
wrapper.vm,
{ query: { issPage: "vehicle-style" } },
undefined,
(c) => c(wrapper.vm)
);
wrapper.vm.backButtonAction();
await nextTick();
//Assert
return apiPromise.finally(() => {
try {
expect(wrapper.vm.$router.navigate).toHaveBeenCalled();
}
catch (e) {
throw e
}
});
});
test("Model set, arePagePrerequisitesValid should be true ", () => {
//Arrange
const { wrapper } = setupMocks({ });
useMainStore().order.vehicle = { year: 2011, make: "ford", model: "mustang", style: null }
//Act
const arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid();
//Assert
expect(arePagePrerequisitesValid).toBe(true);
});
test("there is only one vehicle style => autoselect and move to vehicle damage", async () => {
//Arrange
const { wrapper } = setupMocks({
styleQuestionInitialData: ["2 door sedan"],
});
useMainStore().applicationUser.pageData = {
"part-questions": null,
"vehicle-make": {},
"vehicle-model": {},
"vehicle-style": {},
}
useMainStore().updateVehicleStyle = jest.fn();
useMainStore().setVehicle = jest.fn().mockReturnValue(Promise.resolve())
// Act
await vehicleStyle.beforeRouteEnter.call(
wrapper.vm,
{ query: { issPage: "vehicle-style" } },
undefined,
(c) => c(wrapper.vm)
);
// Assert
expect(useMainStore().updateVehicleStyle).toHaveBeenCalledWith("2 door sedan");
expect(router.overrideNavigation).toHaveBeenCalled();
});
test("there is only one vehicle style and vehicle-damage was visited => don't autoselect or move to vehicle damage", async () => {
//Arrange
const { wrapper } = setupMocks({
styleQuestionInitialData: ["2 door sedan"],
});
useMainStore().updateVehicleStyle = jest.fn();
useMainStore().setVehicle = jest.fn().mockReturnValue(Promise.resolve())
useMainStore().applicationUser.pageData = {
"part-questions": null,
"vehicle-make": {},
"vehicle-model": {},
"vehicle-style": {},
"vehicle-damage": {},
}
// Act
await vehicleStyle.beforeRouteEnter.call(
wrapper.vm,
{ query: { issPage: "vehicle-style" } },
undefined,
(c) => c(wrapper.vm)
);
// Assert
expect(useMainStore().updateVehicleStyle).not.toHaveBeenCalledWith("2 door sedan");
expect(router.overrideNavigation).toHaveBeenCalled();
});
});
function setupMocks({
vehicleStyleQuestionCmsContent = {},
styleQuestionInitialData = {},
pageHeaderWidgetHeaderText = {},
mountOptionsMockData = {},
}) {
//Mock api responses
const apiResponses = {
cmsContent: {
SiteSubHeaderWidget: pageHeaderWidgetHeaderText,
VehicleStyleQuestion: vehicleStyleQuestionCmsContent,
VehicleBannerWidget: {
GenericVehicleImage:
`${applicationConfig.ISS_DEV_CMS_DOMAIN}/images/default-source/default-album/blurred-image.jpg`,
},
SiteHeaderWidget: {
LogoImage:
`${applicationConfig.ISS_DEV_CMS_DOMAIN}/images/default-source/default-album/logos/insuranceLogo.jpg`,
},
},
styleQuestionInitialData: styleQuestionInitialData,
};
const apiPromise = Promise.resolve(apiResponses);
settleAllPromises.mockImplementation(() => apiPromise);
fetchCmsContentForPage.mockImplementation(() => Promise.resolve());
//Mock style question methods
styleQuestion.methods = {
loadInitialData: jest.fn(),
initializeComponent: jest.fn(),
};
const mountOptions = getMountOptions(mountOptionsMockData);
const wrapper = shallowMount(vehicleStyle, mountOptions);
const styleQuestionWrapper = wrapper.findComponent({ name: "styleQuestion" });
styleQuestionWrapper.vm.initializeComponent =
styleQuestion.methods.initializeComponent;
wrapper.vm.setCmsContent = baseMixin.methods.setCmsContent;
return { wrapper, apiPromise };
}

View file

@ -1,124 +0,0 @@
<template>
<div class="page-container-grouped-styles position-relative">
<div class="fade-on-route-transition position-relative">
<siteHeader cmsWidgetName="SiteHeaderWidget" />
<div class="select-car">
<div class="container-fluid pb-2 px-5">
<div class="row">
<div class="col">
<div class="select-car-form rounded text-center">
<vehicleBanner cmsWidgetName="VehicleBannerWidget" class="mb-3" displayGenericVehicleImage />
<siteSubHeader cmsWidgetName="SiteSubHeaderWidget" :hasBackButton="true" :backButtonAccessibleText="backButtonAccessibleText" @click-event="backButtonAction" />
<styleQuestion v-model="selectedStyle" ref="styleQuestion" cmsWidgetName="VehicleStyleQuestion" />
<siteFooter cmsWidgetName="SiteFooterWidget" ref="siteFooter" @back-clicked="backButtonAction" :isForwardButtonHidden="shouldHideForwardButton" />
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
// Components
import styleQuestion from "@/layouts/vehicle-style/style-question/style-question";
import siteHeader from "@/iss-components/site-header/site-header";
import siteSubHeader from "@/iss-components/site-sub-header/site-sub-header";
import vehicleBanner from "@/iss-components/vehicle-banner/vehicle-banner";
import siteFooter from "@/iss-components/site-footer/site-footer";
// Supporting files
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
import { settleAllPromises } from "@/helpers/layout-helper";
import { issPageValues } from "@/router/router-constants/issPage-values"
import { useMainStore } from "@/store";
import router from "@/router";
import { navigationScenarios } from "@/router/router-constants/navigation-scenarios";
export default {
name: "vehicle-style",
data() {
return {
selectedStyle: null,
shouldHideForwardButton: true
};
},
async beforeRouteEnter(to, from, next) {
// Call APIs
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
const styleQuestionInitialDataPromise = styleQuestion.methods.loadInitialData();
// Settle promises and get results
const promiseResultMap = [
{
resultKey: "cmsContent",
promise: cmsContentPromise,
},
{
resultKey: "styleQuestionInitialData",
promise: styleQuestionInitialDataPromise,
},
];
const resultMap = await settleAllPromises(promiseResultMap);
const visitedVehicleDamage = useMainStore().pageData(issPageValues.VEHICLE_DAMAGE) ? true : false;
// If we have exactly one style then navigate directly to vehicle-damage
if (resultMap.styleQuestionInitialData.length === 1 && !visitedVehicleDamage) {
useMainStore().updateVehicleStyle(resultMap.styleQuestionInitialData[0]);
useMainStore().setVehicle().then(() => {
router.overrideNavigation(navigationScenarios.SELECTED_STYLE, to, next, true);
});
} else {
next((vm) => {
vm.setCmsContent(resultMap.cmsContent);
vm.$refs.styleQuestion.initializeComponent(resultMap.styleQuestionInitialData);
});
}
},
methods: {
backButtonAction() {
this.$router.navigate(this.navigationScenarios.CLICKED_BACK, this.$route);
},
arePagePrerequisitesValid() {
if (this.mainStore.order.vehicle.model) {
return true;
}
return false;
},
},
watch: {
selectedStyle(style) {
this.mainStore.updateVehicleStyle( style );
this.mainStore.setVehicle().then(() => {
this.$router.navigate(
this.navigationScenarios.SELECTED_STYLE,
this.$route
);
});
},
},
components: {
styleQuestion,
siteHeader,
siteSubHeader,
vehicleBanner,
siteFooter
},
computed: {
backButtonAccessibleText()
{
return this.getCmsContent(this.cmsWidgetName, "BackButtonAccessibleText")
}
}
};
</script>

View file

@ -1,115 +0,0 @@
import { shallowMount } from "@vue/test-utils";
import { settleAllPromises } from "@/helpers/layout-helper.js";
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
import vehicleYear from "@/layouts/vehicle-year/vehicle-year.vue";
import yearQuestion from "@/layouts/vehicle-year/year-question/year-question";
import baseMixin from "@/mixins/base-mixin.js";
import { getMountOptions } from "@/helpers/unit-test-helper.js";
import { nextTick } from "vue";
import { applicationConfig } from "@/constants/application-config";
// Mock our module for promises.
jest.mock("@/helpers/layout-helper.js", () => ({
settleAllPromises: jest.fn(),
}));
// Mock fetchCmsContentForPage
jest.mock("@/helpers/cms-content-helper", () => ({
fetchCmsContentForPage: jest.fn(),
}));
describe("vehicle-year.vue", () => {
test("Year question component is initized with api data", async() => {
//Arrange
const yearQuestionInitialData = ["2023", "2022", "2021"];
const { wrapper, apiPromise } = setupMocks({
yearQuestionInitialData: yearQuestionInitialData,
});
//Act
vehicleYear.beforeRouteEnter.call(
wrapper.vm,
{ query: { issPage: "vehicle-year" } },
undefined,
(c) => c(wrapper.vm)
);
//Assert
return apiPromise.finally(() => {
try {
expect(yearQuestion.methods.initializeComponent).toHaveBeenCalledWith(
yearQuestionInitialData
);
}
catch (e) {
throw e
}
});
});
});
describe("vehicle-year.vue", () => {
test("arePagePrerequisitesValid should be true ", () => {
//Arrange
const { wrapper } = setupMocks({});
//Act
vehicleYear.beforeRouteEnter.call(
wrapper.vm,
{ query: { issPage: "vehicle-make" } },
undefined,
(c) => c(wrapper.vm)
);
let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid();
//Assert
expect(arePagePrerequisitesValid).toBe(true);
});
});
function setupMocks({
vehicleYearQuestionCmsContent = {},
yearQuestionInitialData = {},
pageHeaderWidgetHeaderText = {},
mountOptionsMockData = {},
}) {
//Mock api responses
const apiResponses = {
cmsContent: {
SiteSubHeaderWidget: { HeaderText: pageHeaderWidgetHeaderText },
VehicleYearQuestion: vehicleYearQuestionCmsContent,
VehicleBannerWidget: {
GenericVehicleImage:
`${applicationConfig.ISS_DEV_CMS_DOMAIN}/images/default-source/default-album/blurred-image.jpg`,
},
SiteHeaderWidget: {
LogoImage:
`${applicationConfig.ISS_DEV_CMS_DOMAIN}/images/default-source/default-album/logos/insuranceLogo.jpg`,
},
},
yearQuestionInitialData: yearQuestionInitialData,
};
const apiPromise = Promise.resolve(apiResponses);
settleAllPromises.mockImplementation(() => apiPromise);
fetchCmsContentForPage.mockImplementation(() => Promise.resolve());
//Mock year question methods
yearQuestion.methods = {
loadInitialData: jest.fn(),
initializeComponent: jest.fn(),
};
const mountOptions = getMountOptions(mountOptionsMockData);
const wrapper = shallowMount(vehicleYear, mountOptions);
const yearQuestionWrapper = wrapper.findComponent({ name: "yearQuestion" });
yearQuestionWrapper.vm.initializeComponent = yearQuestion.methods.initializeComponent;
wrapper.vm.setCmsContent = baseMixin.methods.setCmsContent;
return { wrapper, apiPromise };
}

View file

@ -1,101 +0,0 @@
<template>
<div class="page-container-grouped-styles position-relative">
<div class="fade-on-route-transition position-relative">
<siteHeader cmsWidgetName="SiteHeaderWidget" />
<div class="select-car">
<div class="container-fluid pb-2 px-5">
<div class="row">
<div class="col">
<div class="select-car-form rounded text-center">
<vehicleBanner cmsWidgetName="VehicleBannerWidget" :displayGenericVehicleImage="true" class="mb-3" />
<siteSubHeader cmsWidgetName="SiteSubHeaderWidget" />
<yearQuestion v-model="selectedYear" ref="yearQuestion" cmsWidgetName="VehicleYearQuestion" />
<siteFooter cmsWidgetName="SiteFooterWidget" ref="siteFooter" @back-clicked="backButtonAction" :isForwardButtonHidden="shouldHideForwardButton" />
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
// Components
import yearQuestion from "@/layouts/vehicle-year/year-question/year-question";
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 vehicleBanner from "@/iss-components/vehicle-banner/vehicle-banner";
// Supporting files
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
import { settleAllPromises } from "@/helpers/layout-helper";
export default {
name: "vehicle-year",
data() {
return {
selectedYear: null,
shouldHideForwardButton: true
};
},
computed: {},
async beforeRouteEnter(to, from, next) {
// Call APIs
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
const yearQuestionInitialDataPromise = yearQuestion.methods.loadInitialData();
// Settle promises and get results
const promiseResultMap = [
{
resultKey: "cmsContent",
promise: cmsContentPromise,
},
{
resultKey: "yearQuestionInitialData",
promise: yearQuestionInitialDataPromise,
},
];
let resultMap = await settleAllPromises(promiseResultMap);
// Call the "next" function to complete the transition to this page.
next((vm) => {
vm.setCmsContent(resultMap.cmsContent);
vm.$refs.yearQuestion.initializeComponent(
resultMap.yearQuestionInitialData
);
});
},
watch: {
selectedYear(year) {
const parsedYear = parseInt(year);
this.mainStore.updateVehicleYear( parsedYear );
this.$router.navigate(
this.navigationScenarios.SELECTED_YEAR,
this.$route
);
},
},
methods: {
arePagePrerequisitesValid() {
return true;
},
backButtonAction() {
this.$router.navigate(this.navigationScenarios.CLICKED_BACK, this.$route);
},
},
components: {
yearQuestion,
siteHeader,
siteSubHeader,
vehicleBanner,
siteFooter
},
};
</script>

View file

@ -1,70 +0,0 @@
import yearQuestion from "@/layouts/vehicle-year/year-question/year-question";
import { shallowMount } from "@vue/test-utils";
import { getMountOptions } from "@/helpers/unit-test-helper.js";
import { useMainStore } from "@/store";
describe("year-question.vue", () => {
test("Selected year is emitted upon selection.", async () => {
//Arrange
const { wrapper } = setupMocks({ modelValueProp: 2020 });
const yearToSelect = 2021;
//Act
wrapper.setValue({ modelValue: yearToSelect });
await wrapper.vm.$nextTick();
//Assert
expect(wrapper.emitted()["update:modelValue"][0]).toEqual([
{ modelValue: 2021 },
]);
});
});
describe("year-question.vue", () => {
test("Data from store api are used as radio question answers.", async () => {
//Arrange
const { wrapper, cmsContent } = setupMocks({
dataFromStoreApi: [2023, 2022, 2021],
});
//Act
const initialData = yearQuestion.methods.loadInitialData.call(wrapper.vm);
yearQuestion.methods.initializeComponent.call(
wrapper.vm,
initialData
);
//Assert
const buttonQuestionComponent = await wrapper.findComponent({
name: "buttonQuestion",
});
expect(buttonQuestionComponent.attributes("answers")).toBe(
"2023,2022,2021"
);
});
});
function setupMocks({
modelValueProp = 1900,
cmsQuestionText = "CMS text goes here",
dataFromStoreApi = [],
}) {
const mountOptions = getMountOptions();
const store = useMainStore();
store.getVehicleYears = jest.fn(() => dataFromStoreApi);
//Mock props
mountOptions.propsData = {
modelValue: modelValueProp,
};
const wrapper = shallowMount(yearQuestion, mountOptions);
//Mock CMS content
const cmsContent = {
QuestionText: cmsQuestionText,
};
return { wrapper, cmsContent };
}

View file

@ -1,56 +0,0 @@
<template>
<buttonQuestion
class="radioQuestion"
isOverflowScrollable
selectingInitiatesLoad
:questionText="questionText"
:answers="years"
groupName="ChooseVehicleYear"
textPosition="text-start"
v-model="selectedValue"
isRequired
/>
</template>
<script>
import buttonQuestion from "@/digital-components/button-question/button-question";
import { useMainStore } from '@/store';
export default {
name: "year-question",
data() {
return {
years: [],
};
},
props: {
modelValue: Number,
cmsWidgetName: String,
},
components: {
buttonQuestion,
},
computed: {
questionText(){
return this.getCmsContent(this.cmsWidgetName, 'QuestionText');
},
selectedValue: {
get: function() {
return this.modelValue
},
set: function(newValue) {
this.$emit("update:modelValue", newValue);
}
}
},
methods: {
loadInitialData() {
return useMainStore().getVehicleYears();
},
initializeComponent(initialData) {
this.years = initialData;
},
},
};
</script>