Merge branch 'develop' into feature/Digital/SSR-51
This commit is contained in:
commit
75f8da12bc
33 changed files with 1033 additions and 111 deletions
44
package-lock.json
generated
44
package-lock.json
generated
|
|
@ -17717,6 +17717,29 @@
|
|||
"webpack-merge": "^5.7.3",
|
||||
"webpack-virtual-modules": "^0.4.2",
|
||||
"whatwg-fetch": "^3.6.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@vue/vue-loader-v15": {
|
||||
"version": "npm:vue-loader@15.10.0",
|
||||
"resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-15.10.0.tgz",
|
||||
"integrity": "sha512-VU6tuO8eKajrFeBzMssFUP9SvakEeeSi1BxdTH5o3+1yUyrldp8IERkSdXlMI2t4kxF2sqYUDsQY+WJBxzBmZg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@vue/component-compiler-utils": "^3.1.0",
|
||||
"hash-sum": "^1.0.2",
|
||||
"loader-utils": "^1.1.0",
|
||||
"vue-hot-reload-api": "^2.3.0",
|
||||
"vue-style-loader": "^4.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"hash-sum": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-1.0.2.tgz",
|
||||
"integrity": "sha512-fUs4B4L+mlt8/XAtSOGMUO1TXmAelItBPtJG7CyHJfYTdDjwisntGO2JQz7oUsatOY9o68+57eziUVNw/mRHmA==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@vue/cli-shared-utils": {
|
||||
|
|
@ -17967,27 +17990,6 @@
|
|||
"dev": true,
|
||||
"requires": {}
|
||||
},
|
||||
"@vue/vue-loader-v15": {
|
||||
"version": "npm:vue-loader@15.10.0",
|
||||
"resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-15.10.0.tgz",
|
||||
"integrity": "sha512-VU6tuO8eKajrFeBzMssFUP9SvakEeeSi1BxdTH5o3+1yUyrldp8IERkSdXlMI2t4kxF2sqYUDsQY+WJBxzBmZg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@vue/component-compiler-utils": "^3.1.0",
|
||||
"hash-sum": "^1.0.2",
|
||||
"loader-utils": "^1.1.0",
|
||||
"vue-hot-reload-api": "^2.3.0",
|
||||
"vue-style-loader": "^4.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"hash-sum": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-1.0.2.tgz",
|
||||
"integrity": "sha512-fUs4B4L+mlt8/XAtSOGMUO1TXmAelItBPtJG7CyHJfYTdDjwisntGO2JQz7oUsatOY9o68+57eziUVNw/mRHmA==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"@vue/vue3-jest": {
|
||||
"version": "27.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@vue/vue3-jest/-/vue3-jest-27.0.0.tgz",
|
||||
|
|
|
|||
|
|
@ -3,12 +3,16 @@
|
|||
<head>
|
||||
<script>
|
||||
window.dataLayer = [{}];
|
||||
</script>
|
||||
<script><%= process.env.VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY %></script>
|
||||
</script>
|
||||
<script><%= process.env.VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY %></script>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,300;0,400;0,500;0,700;1,300;1,400;1,500;1,700&display=swap" rel="stylesheet">
|
||||
|
||||
<title><%= htmlWebpackPlugin.options.title %></title>
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
|||
|
|
@ -225,7 +225,7 @@
|
|||
margin-top: 1.5rem;
|
||||
margin-bottom: 1rem;
|
||||
font-size: 1rem;
|
||||
line-height: 1.625rem;
|
||||
line-height: 1.5rem;
|
||||
|
||||
& > span {
|
||||
text-align: center;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
import { shallowMount } from "@vue/test-utils";
|
||||
import buttonBack from "./button-back";
|
||||
|
||||
describe("back button", () => {
|
||||
test("renders a button", () => {
|
||||
// Arrange
|
||||
const myFunction = () => {};
|
||||
|
||||
// Act
|
||||
const wrapper = shallowMount(buttonBack, {
|
||||
propsData: {
|
||||
backButtonAction: myFunction,
|
||||
backButtonAccessibleText: "something",
|
||||
},
|
||||
});
|
||||
|
||||
// Assert
|
||||
expect(wrapper.find("button").exists()).toBe(true);
|
||||
wrapper.unmount();
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
<template>
|
||||
<button
|
||||
@click="handleClick"
|
||||
class="back-button-wrapper"
|
||||
:aria-label="backButtonAccessibleText"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="34px"
|
||||
height="30px"
|
||||
viewBox="-2.2 -6 30 30"
|
||||
>
|
||||
<g id="Layer_3">
|
||||
<path
|
||||
class="outer"
|
||||
fill="#FFFFFF"
|
||||
d="M19.934-1.434h-8.486c-1.683,0-2.999,0.528-4.021,1.614L1.685,6.146C0.78,7.079,0.338,8.027,0.338,9.041
|
||||
c0,1.028,0.444,1.979,1.359,2.908l5.753,5.938c1.054,1.093,2.403,1.647,4.007,1.647l8.475,0.01c2.861,0,4.568-1.692,4.568-4.528
|
||||
V3.094C24.5,0.259,22.793-1.434,19.934-1.434L19.934-1.434z"
|
||||
/>
|
||||
</g>
|
||||
<g id="Layer_2">
|
||||
<path
|
||||
class="inner"
|
||||
fill="#727676"
|
||||
d="M19.934,17.989c2.041,0,3.066-1.006,3.066-3.028V3.039c0-2.022-1.025-3.028-3.066-3.028h-8.486
|
||||
c-1.143,0-2.129,0.292-2.929,1.143L2.766,7.13C2.131,7.784,1.838,8.37,1.838,8.985c0,0.605,0.283,1.201,0.928,1.855l5.762,5.947
|
||||
c0.811,0.84,1.787,1.191,2.93,1.191L19.934,17.989z M10.773,13.253c-0.439,0-0.801-0.371-0.801-0.82
|
||||
c0-0.215,0.078-0.42,0.235-0.566l2.861-2.861l-2.861-2.862c-0.156-0.156-0.234-0.352-0.234-0.566c0-0.458,0.362-0.801,0.801-0.801
|
||||
c0.224,0,0.41,0.069,0.556,0.225l2.881,2.872l2.891-2.881c0.166-0.166,0.353-0.234,0.566-0.234c0.439,0,0.801,0.352,0.801,0.801
|
||||
c0,0.225-0.078,0.4-0.234,0.576l-2.871,2.871l2.861,2.852c0.146,0.156,0.234,0.352,0.234,0.576c0,0.449-0.361,0.82-0.811,0.82
|
||||
c-0.225,0-0.43-0.098-0.586-0.244l-2.852-2.871l-2.852,2.871C11.203,13.165,10.999,13.253,10.773,13.253z"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
</button>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "buttonBack",
|
||||
props: {
|
||||
backButtonAccessibleText: {
|
||||
type: String,
|
||||
required: true,
|
||||
default: "",
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
handleClick() {
|
||||
this.$emit("click-event");
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.back-button-wrapper {
|
||||
padding: 0;
|
||||
position: relative;
|
||||
top: -1px;
|
||||
margin-left: 2px;
|
||||
border: none;
|
||||
background: none;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
|
||||
svg .outer {
|
||||
fill: $white;
|
||||
stroke-width: 2.5px;
|
||||
stroke: $blue;
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
transform: translate(-2.7px, -1.8px) scale(1.2);
|
||||
}
|
||||
}
|
||||
&:focus-visible {
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -5,23 +5,39 @@
|
|||
<span>
|
||||
{{ content }}
|
||||
</span>
|
||||
<buttonBack
|
||||
v-if="hasBackButton"
|
||||
:backButtonAccessibleText="backButtonAccessibleText"
|
||||
@click-event="clickEvent"
|
||||
/>
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import buttonBack from "@/common-components/site-sub-header/button-back/button-back";
|
||||
|
||||
|
||||
export default ({
|
||||
name: "siteSubHeader",
|
||||
props: {
|
||||
cmsWidgetName: String,
|
||||
hasBackButton: Boolean,
|
||||
backButtonAccessibleText: String,
|
||||
},
|
||||
computed: {
|
||||
content()
|
||||
{
|
||||
return this.getCmsContent(this.cmsWidgetName, "SubHeaderText")
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
clickEvent() {
|
||||
this.$emit("click-event");
|
||||
},
|
||||
},
|
||||
components: { buttonBack },
|
||||
})
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import { useMainStore } from "@/store";
|
||||
export default {
|
||||
name: "vehicle-banner",
|
||||
props: {
|
||||
|
|
@ -25,7 +25,7 @@ export default {
|
|||
return this.genericVehicleImage;
|
||||
}
|
||||
|
||||
const imageUrl = this.mainStore.order.vehicle.imageUrl;
|
||||
const imageUrl = useMainStore().order.vehicle.imageUrl;
|
||||
if (!imageUrl || imageUrl === "NULL"){
|
||||
return this.getUnmatchedVehicleIcon();
|
||||
}
|
||||
|
|
@ -53,7 +53,7 @@ export default {
|
|||
},
|
||||
methods: {
|
||||
getUnmatchedVehicleIcon(){
|
||||
switch(this.mainStore.order.vehicle.category){
|
||||
switch(useMainStore().order.vehicle.category){
|
||||
case this.vehicleCategories.CAR:
|
||||
return this.carUnmatchedVehicleIcon;
|
||||
case this.vehicleCategories.SUV:
|
||||
|
|
|
|||
|
|
@ -15,6 +15,14 @@ const endpoints = {
|
|||
url: "/vehicle/api/v1/vehicle/years",
|
||||
method: "GET",
|
||||
},
|
||||
GetVehicleMakes: {
|
||||
url: "/vehicle/api/v1/vehicle/makes/",
|
||||
method: "GET",
|
||||
},
|
||||
GetVehicleModels: {
|
||||
url: "/vehicle/api/v1/vehicle/Models",
|
||||
method: "GET",
|
||||
},
|
||||
GetPageData: {
|
||||
url: (applicationAbbreviation, pageName) =>
|
||||
`/content/api/v1/content/${applicationAbbreviation}/${pageName}`,
|
||||
|
|
|
|||
|
|
@ -12,8 +12,8 @@ export default {
|
|||
const cfDistroUrl = applicationConfig.CONSUMER_CF_DISTRO;
|
||||
const payloadAndAnalyticsData = Object.assign({}, payload, { AppName: "SelfService" });
|
||||
const headers = {
|
||||
[headerKeys.EXPERIMENT]: JSON.stringify(useMainStore.getters.experimentSettings),
|
||||
};
|
||||
[headerKeys.EXPERIMENT]: JSON.stringify(useMainStore.experimentSettings),
|
||||
};
|
||||
|
||||
axios({
|
||||
method: method,
|
||||
|
|
|
|||
|
|
@ -89,14 +89,14 @@ function mapStringToState(str) {
|
|||
const regexMatches = [...str.matchAll(regexExp)];
|
||||
const globalStateMatches = regexMatches.filter(match => {
|
||||
return match[1] === dynamicStrings.GLOBAL_STATE;
|
||||
})
|
||||
});
|
||||
|
||||
// Our final string value that will be built from the matches.
|
||||
let stringBuilder = "";
|
||||
|
||||
for (const match of globalStateMatches) {
|
||||
// Reset store state for each match.
|
||||
let storeState = useMainStore().state;
|
||||
let storeState = useMainStore();
|
||||
|
||||
for (const s of match[2].split(".")) {
|
||||
if (storeState[s] != undefined) {
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ import { externalUrls } from "@/router/router-constants/externalUrl-values";
|
|||
import { queryStrings } from "@/constants/query-strings";
|
||||
import { fmgPageValues } from "@/router/router-constants/fmgPage-values";
|
||||
|
||||
import { useMainStore } from "@/store";
|
||||
import router from "@/router";
|
||||
|
||||
// Mock Lazy Load
|
||||
|
|
@ -343,52 +342,6 @@ describe("navigateToHeritageFunnel", () => {
|
|||
saveSessionFunction.mockRestore();
|
||||
});
|
||||
|
||||
test("should go to heritage funnel", async () => {
|
||||
// Arrange
|
||||
const mockReferralNumber = "2";
|
||||
const mockCorrelationId = "55";
|
||||
const mockReferralDate = "2022";
|
||||
const mockAccountNumber = "167132";
|
||||
const mockSavedSessionId = "xxx-xxx-xxx";
|
||||
const mockCrmCustomerId = "xxx-xxx-xxx";
|
||||
|
||||
const mockOrderInfo = getMockOrderInfo(
|
||||
mockReferralNumber,
|
||||
mockCorrelationId,
|
||||
mockReferralDate,
|
||||
mockAccountNumber,
|
||||
mockSavedSessionId,
|
||||
mockCrmCustomerId
|
||||
);
|
||||
|
||||
const mockData = {
|
||||
actionList: [
|
||||
{
|
||||
actionName: storeActions.SAVE_SESSION,
|
||||
data: mockOrderInfo,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
setupMocksForJsFiles(mockData);
|
||||
|
||||
useMainStore.getters.order.referralCorrelationId = mockCorrelationId;
|
||||
|
||||
router.navigateToExternalUrl = jest.fn();
|
||||
|
||||
// Act
|
||||
await navigateToHeritageFunnel();
|
||||
|
||||
// Assert
|
||||
expect(router.navigateToExternalUrl).toHaveBeenCalled();
|
||||
expect(router.navigateToExternalUrl).toHaveBeenCalledWith(
|
||||
externalUrls.HERITAGE_FUNNEL,
|
||||
expect.objectContaining({
|
||||
corid: mockCorrelationId,
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
test("should not save session, but should still navigate", async () => {
|
||||
// Arrange
|
||||
const mockReferralNumber = "2";
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { storeActions } from "@/constants/store-actions";
|
|||
import { navigationScenarios } from "@/router/router-constants/navigation-scenarios.js";
|
||||
import { vehicleCategories } from "@/constants/vehicle-categories.js";
|
||||
import { issPageValues } from "@/router/router-constants/issPage-values";
|
||||
import { fmgPageValues } from "@/router/router-constants/fmgPage-values";
|
||||
import { Form } from "vee-validate";
|
||||
import { queryStrings } from "@/constants/query-strings";
|
||||
import { useMainStore } from "@/store";
|
||||
|
|
@ -50,6 +51,7 @@ export function getMountOptions(mockData) {
|
|||
mocks.navigationScenarios = navigationScenarios;
|
||||
mocks.vehicleCategories = vehicleCategories;
|
||||
mocks.fmgPageValues = fmgPageValues;
|
||||
mocks.issPageValues = issPageValues;
|
||||
mocks.analyticsPageEvents = analyticsPageEvents;
|
||||
mocks.GaCategories = GaCategories;
|
||||
mocks.GaActions = GaActions;
|
||||
|
|
|
|||
70
src/layouts/vehicle-make/make-question/make-question.spec.js
Normal file
70
src/layouts/vehicle-make/make-question/make-question.spec.js
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
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 };
|
||||
}
|
||||
56
src/layouts/vehicle-make/make-question/make-question.vue
Normal file
56
src/layouts/vehicle-make/make-question/make-question.vue
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
<template>
|
||||
<buttonQuestion
|
||||
class="radioQuestion"
|
||||
isOverflowScrollable
|
||||
selectingInitiatesLoad
|
||||
:questionText="questionText"
|
||||
:answers="makes"
|
||||
groupName="ChooseVehicleMake"
|
||||
textPosition="text-start"
|
||||
v-model="selectedValue"
|
||||
isRequired
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import buttonQuestion from "@/common-components/button-question/button-question";
|
||||
import { useMainStore } from '@/store';
|
||||
|
||||
export default {
|
||||
name: "make-question",
|
||||
data() {
|
||||
return {
|
||||
makes: Array,
|
||||
};
|
||||
},
|
||||
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>
|
||||
|
||||
|
|
@ -1 +1,140 @@
|
|||
test.todo("some test to be written in the future");
|
||||
// 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";
|
||||
|
||||
// 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
|
||||
apiPromise.finally(() => {
|
||||
expect(makeQuestion.methods.initializeComponent).toHaveBeenCalledWith(
|
||||
makeQuestionInitialData
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
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
|
||||
apiPromise.finally(() => {
|
||||
expect(wrapper.vm.$router.navigate).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
test("Year set, arePagePrerequisitesValid should be true ", async () => {
|
||||
//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:
|
||||
"https://digitalisscms.dev.safelite.io/images/default-source/default-album/blurred-image.jpg",
|
||||
},
|
||||
SiteHeaderWidget: {
|
||||
LogoImage:
|
||||
"https://digitalisscms.dev.safelite.io/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 };
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,28 +1,102 @@
|
|||
<template>
|
||||
<div>
|
||||
<input type="text" v-model="year"/>
|
||||
<span> Vehicle Make Placeholder </span>
|
||||
<span>{{returnVehicleYear}}</span>
|
||||
<button @click="updateVehicleYear(year)">Add</button>
|
||||
<div class="page-container-grouped-styles">
|
||||
<siteHeader cmsWidgetName="SiteHeaderWidget" />
|
||||
<div class="select-car">
|
||||
<div class="select-car-form rounded text-center">
|
||||
<vehicleBanner cmsWidgetName="VehicleBannerWidget" :displayGenericVehicleImage="true"/>
|
||||
<siteSubHeader
|
||||
cmsWidgetName="SiteSubHeaderWidget"
|
||||
:hasBackButton="true"
|
||||
@click-event="backButtonAction"
|
||||
backButtonAccessibleText = "Change vehicle year"
|
||||
/>
|
||||
<div class="fade-on-route-transition">
|
||||
<makeQuestion
|
||||
class="fade-on-route-transition"
|
||||
v-model="selectedMake"
|
||||
ref="makeQuestion"
|
||||
cmsWidgetName="VehicleMakeQuestion"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// Components
|
||||
import makeQuestion from "@/layouts/vehicle-make/make-question/make-question";
|
||||
import siteHeader from "@/common-components/site-header/site-header";
|
||||
import siteSubHeader from "@/common-components/site-sub-header/site-sub-header";
|
||||
import vehicleBanner from "@/common-components/vehicle-banner/vehicle-banner";
|
||||
|
||||
// Supporting files
|
||||
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
|
||||
import { settleAllPromises } from "@/helpers/layout-helper";
|
||||
|
||||
export default {
|
||||
name: 'vehicle-make',
|
||||
methods:
|
||||
{
|
||||
updateVehicleYear(item)
|
||||
{
|
||||
this.mainStore.updateVehicleYear(item);
|
||||
}
|
||||
data() {
|
||||
return {
|
||||
selectedMake: null,
|
||||
};
|
||||
},
|
||||
computed:
|
||||
{
|
||||
returnVehicleYear()
|
||||
|
||||
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 = [
|
||||
{
|
||||
return this.mainStore.order.vehicle.year;
|
||||
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,
|
||||
},
|
||||
watch: {
|
||||
selectedMake(make) {
|
||||
this.mainStore.updateVehicleMake(make);
|
||||
this.$router.navigate(
|
||||
this.navigationScenarios.SELECTED_MAKE,
|
||||
this.$route
|
||||
);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
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 };
|
||||
}
|
||||
56
src/layouts/vehicle-model/model-question/model-question.vue
Normal file
56
src/layouts/vehicle-model/model-question/model-question.vue
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
<template>
|
||||
<buttonQuestion
|
||||
class="radioQuestion"
|
||||
isOverflowScrollable
|
||||
selectingInitiatesLoad
|
||||
:questionText="questionText"
|
||||
:answers="models"
|
||||
groupName="ChooseVehicleModel"
|
||||
textPosition="text-start"
|
||||
v-model="selectedValue"
|
||||
isRequired
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import buttonQuestion from "@/common-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>
|
||||
|
||||
138
src/layouts/vehicle-model/vehicle-model.spec.js
Normal file
138
src/layouts/vehicle-model/vehicle-model.spec.js
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
// 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";
|
||||
|
||||
// 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
|
||||
apiPromise.finally(() => {
|
||||
expect(modelQuestion.methods.initializeComponent).toHaveBeenCalledWith(
|
||||
modelQuestionInitialData
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("vehicle-model.vue", () => {
|
||||
test("BackButtonAction triggers a router.navigateWithoutSaving 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
|
||||
apiPromise.finally(() => {
|
||||
expect(wrapper.vm.$router.navigate).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
describe("vehicle-model.vue", () => {
|
||||
test("Make set, arePagePrerequisitesValid should be true ", async () => {
|
||||
//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();
|
||||
await nextTick();
|
||||
|
||||
//Assert
|
||||
expect(arePagePrerequisitesValid).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
function setupMocks({
|
||||
buttonQuestionContent = {},
|
||||
modelQuestionInitialData = {},
|
||||
pageHeaderWidgetHeaderText = {},
|
||||
mountOptionsMockData = {},
|
||||
}) {
|
||||
//Mock api responses
|
||||
const apiResponses = {
|
||||
cmsContent: {
|
||||
FunnelSubHeaderWidget: pageHeaderWidgetHeaderText,
|
||||
VehicleModelQuestion: buttonQuestionContent,
|
||||
VehicleBannerWidget: {
|
||||
GenericVehicleImage:
|
||||
"https://digitalisscms.dev.safelite.io/images/default-source/default-album/blurred-image.jpg",
|
||||
},
|
||||
FunnelHeaderWidget: {
|
||||
LogoImage:
|
||||
"https://digitalisscms.dev.safelite.io/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 };
|
||||
}
|
||||
103
src/layouts/vehicle-model/vehicle-model.vue
Normal file
103
src/layouts/vehicle-model/vehicle-model.vue
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
<template>
|
||||
<div class="page-container-grouped-styles">
|
||||
<siteHeader cmsWidgetName="SiteHeaderWidget" />
|
||||
<div class="select-car">
|
||||
<div class="select-car-form rounded text-center">
|
||||
<vehicleBanner cmsWidgetName="VehicleBannerWidget" displayGenericVehicleImage />
|
||||
<siteSubHeader
|
||||
cmsWidgetName="SiteSubHeaderWidget"
|
||||
:hasBackButton="true"
|
||||
@click-event="backButtonAction"
|
||||
backButtonAccessibleText = "Change vehicle make"
|
||||
/>
|
||||
<div class="fade-on-route-transition">
|
||||
<modelQuestion v-model="selectedModel" ref="modelQuestion" cmsWidgetName="VehicleModelQuestion" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// Components
|
||||
import modelQuestion from "@/layouts/vehicle-model/model-question/model-question";
|
||||
import siteHeader from "@/common-components/site-header/site-header";
|
||||
import siteSubHeader from "@/common-components/site-sub-header/site-sub-header";
|
||||
import vehicleBanner from "@/common-components/vehicle-banner/vehicle-banner";
|
||||
|
||||
// Supporting files
|
||||
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
|
||||
import { settleAllPromises } from "@/helpers/layout-helper";
|
||||
|
||||
export default {
|
||||
name: "vehicle-model",
|
||||
data() {
|
||||
return {
|
||||
selectedModel: null,
|
||||
};
|
||||
},
|
||||
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;
|
||||
},
|
||||
},
|
||||
|
||||
watch: {
|
||||
selectedModel(model) {
|
||||
this.mainStore.updateVehicleYear(model);
|
||||
this.$router.navigate(
|
||||
this.navigationScenarios.SELECTED_MODEL,
|
||||
this.$route
|
||||
);
|
||||
},
|
||||
},
|
||||
|
||||
components: {
|
||||
modelQuestion,
|
||||
siteHeader,
|
||||
siteSubHeader,
|
||||
vehicleBanner,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
|
|
@ -5,6 +5,7 @@ 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";
|
||||
|
||||
|
||||
// Mock our module for promises.
|
||||
|
|
@ -43,6 +44,27 @@ describe("vehicle-year.vue", () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe("vehicle-year.vue", () => {
|
||||
test("arePagePrerequisitesValid should be true ", async () => {
|
||||
//Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
|
||||
//Act
|
||||
vehicleYear.beforeRouteEnter.call(
|
||||
wrapper.vm,
|
||||
{ query: { issPage: "vehicle-make" } },
|
||||
undefined,
|
||||
(c) => c(wrapper.vm)
|
||||
);
|
||||
|
||||
let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid();
|
||||
await nextTick();
|
||||
|
||||
//Assert
|
||||
expect(arePagePrerequisitesValid).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
function setupMocks({
|
||||
vehicleYearQuestionCmsContent = {},
|
||||
yearQuestionInitialData = {},
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
<siteHeader cmsWidgetName="SiteHeaderWidget" />
|
||||
<div class="select-car">
|
||||
<div class="select-car-form rounded text-center">
|
||||
<vehicleBanner cmsWidgetName="VehicleBannerWidget" displayGenericVehicleImage="true"/>
|
||||
<vehicleBanner cmsWidgetName="VehicleBannerWidget" :displayGenericVehicleImage="true"/>
|
||||
<siteSubHeader cmsWidgetName="SiteSubHeaderWidget" />
|
||||
<div class="fade-on-route-transition">
|
||||
<yearQuestion
|
||||
|
|
@ -65,6 +65,22 @@
|
|||
);
|
||||
});
|
||||
},
|
||||
|
||||
watch: {
|
||||
selectedYear(year) {
|
||||
const parsedYear = parseInt(year);
|
||||
this.mainStore.updateVehicleYear(parsedYear);
|
||||
this.$router.navigate(
|
||||
this.navigationScenarios.SELECTED_YEAR,
|
||||
this.$route
|
||||
);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
arePagePrerequisitesValid() {
|
||||
return true;
|
||||
},
|
||||
},
|
||||
|
||||
components: {
|
||||
yearQuestion,
|
||||
|
|
|
|||
|
|
@ -3,6 +3,23 @@ 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
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ export default {
|
|||
action: "",
|
||||
event: pageEvent,
|
||||
shouldUseSessionId: false,
|
||||
experimentsForUser: useMainStore.getters.applicationUserObj.experiments,
|
||||
experimentsForUser: useMainStore.applicationUserObj.experiments,
|
||||
};
|
||||
|
||||
baseMixin.methods.dispatchStoreAction(storeActions.LOG_PAGE_VIEW, payload, false);
|
||||
|
|
@ -53,7 +53,7 @@ export default {
|
|||
label: label,
|
||||
value: value,
|
||||
shouldUseSessionId: false,
|
||||
experimentsForUser: useMainStore.getters.applicationUserObj.experiments,
|
||||
experimentsForUser: useMainStore.applicationUserObj.experiments,
|
||||
};
|
||||
|
||||
baseMixin.methods.dispatchStoreAction(storeActions.LOG_CUSTOM_EVENT, payload, false);
|
||||
|
|
@ -93,7 +93,7 @@ export default {
|
|||
},
|
||||
|
||||
pushExperimentsToDataLayer() {
|
||||
const experiments = useMainStore.getters.applicationUserObj.experiments;
|
||||
const experiments = useMainStore.applicationUserObj.experiments;
|
||||
experiments?.forEach((exp) => {
|
||||
// Set Google Dimension Index based on experiment settings.
|
||||
let googleDimensionIndex = 99;
|
||||
|
|
|
|||
|
|
@ -131,7 +131,7 @@ describe("analyticsMixin.js", () => {
|
|||
// Assert
|
||||
expect(expectedDataLayer).toEqual(expect.arrayContaining(window.dataLayer));
|
||||
});
|
||||
|
||||
/*
|
||||
test("Experiments, should push to dataLayer with default Google Custom Dimension Index", () => {
|
||||
// Arrange
|
||||
window.dataLayer = [];
|
||||
|
|
@ -154,7 +154,7 @@ describe("analyticsMixin.js", () => {
|
|||
);
|
||||
|
||||
useMainStore.getters = {
|
||||
applicationUser: {
|
||||
applicationUserObj: {
|
||||
experiments: [
|
||||
{
|
||||
settings: {},
|
||||
|
|
@ -202,7 +202,7 @@ describe("analyticsMixin.js", () => {
|
|||
);
|
||||
|
||||
useMainStore.getters = {
|
||||
applicationUser: {
|
||||
applicationUserObj: {
|
||||
experiments: [
|
||||
{
|
||||
settings: { "Google Custom Dimension Index": "5" },
|
||||
|
|
@ -227,7 +227,7 @@ describe("analyticsMixin.js", () => {
|
|||
},
|
||||
]);
|
||||
});
|
||||
|
||||
*/
|
||||
test("Obj is not null after action prepended", () => {
|
||||
//Arrange
|
||||
const obj = { baseMethodName: "testMethodName", data: "testData" };
|
||||
|
|
|
|||
|
|
@ -3,14 +3,14 @@ import { useMainStore } from "@/store";
|
|||
export default {
|
||||
methods: {
|
||||
hasSettingEqualTo(settingName, settingValue) {
|
||||
return useMainStore.getters.experimentSettings[settingName] == settingValue;
|
||||
return useMainStore.experimentSettings[settingName] == settingValue;
|
||||
},
|
||||
hasSetting(settingName) {
|
||||
return Object.hasOwn( useMainStore.getters.experimentSettings, settingName);
|
||||
return Object.hasOwn( useMainStore.experimentSettings, settingName);
|
||||
},
|
||||
getSettingValue(settingName) {
|
||||
return this.hasSetting(settingName)
|
||||
? useMainStore.getters.experimentSettings[settingName]
|
||||
? useMainStore.experimentSettings[settingName]
|
||||
: null;
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -3,5 +3,6 @@ export const issPageValues = {
|
|||
WELCOME_PAGE: "welcome-page",
|
||||
VEHICLE_MAKE: "vehicle-make",
|
||||
VEHICLE_YEAR: "vehicle-year",
|
||||
VEHICLE_MODEL: "vehicle-model"
|
||||
};
|
||||
|
||||
|
|
@ -5,7 +5,9 @@ const navigationScenarios = {
|
|||
|
||||
// YMMS
|
||||
SELECTED_YEAR: "SELECTED_YEAR",
|
||||
|
||||
SELECTED_MAKE: "SELECTED_MAKE",
|
||||
SELECTED_MODEL: "SELECTED_MODEL",
|
||||
|
||||
// TESTING
|
||||
CLICKED_TEST: "CLICKED_TEST"
|
||||
};
|
||||
|
|
|
|||
|
|
@ -11,8 +11,38 @@ const routingTable = function(store) {
|
|||
scenario: navigationScenarios.CLICKED_BACK,
|
||||
destinationIssPageValue: issPageValues.WELCOME_PAGE
|
||||
},
|
||||
{
|
||||
scenario: navigationScenarios.SELECTED_YEAR,
|
||||
destinationIssPageValue: issPageValues.VEHICLE_MAKE
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
issPageValue: issPageValues.VEHICLE_MAKE,
|
||||
maps: [
|
||||
{
|
||||
scenario: navigationScenarios.CLICKED_BACK,
|
||||
destinationIssPageValue: issPageValues.VEHICLE_YEAR
|
||||
},
|
||||
{
|
||||
scenario: navigationScenarios.SELECTED_MAKE,
|
||||
destinationIssPageValue: issPageValues.VEHICLE_MODEL
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
issPageValue: issPageValues.VEHICLE_MODEL,
|
||||
maps: [
|
||||
{
|
||||
scenario: navigationScenarios.CLICKED_BACK,
|
||||
destinationIssPageValue: issPageValues.VEHICLE_MAKE,
|
||||
},
|
||||
{
|
||||
scenario: navigationScenarios.SELECTED_MODEL,
|
||||
destinationUrl: "https://www.google.com"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
issPageValue: issPageValues.WELCOME_PAGE,
|
||||
maps: [
|
||||
|
|
@ -26,6 +56,7 @@ const routingTable = function(store) {
|
|||
}
|
||||
]
|
||||
},
|
||||
|
||||
];
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { defineStore, createPinia } from "pinia";
|
||||
import { defineStore } from "pinia";
|
||||
import { endpoints } from "@/constants/endpoints.js";
|
||||
import { getDateForSavedSessionTimeout } from "@/helpers/heritage-integration/session-helper";
|
||||
import globalMethods from "@/global-methods";
|
||||
|
|
@ -160,6 +160,22 @@ export const useMainStore = defineStore({
|
|||
});
|
||||
},
|
||||
|
||||
getVehicleMakes() {
|
||||
return globalMethods.callHttpClient({
|
||||
method: endpoints.GetVehicleMakes.method,
|
||||
endpoint: endpoints.GetVehicleMakes.url + this.order.vehicle.year,
|
||||
payload: {},
|
||||
});
|
||||
},
|
||||
|
||||
getVehicleModels() {
|
||||
return globalMethods.callHttpClient({
|
||||
method: endpoints.GetVehicleModels.method,
|
||||
endpoint: `${endpoints.GetVehicleModels.url}/${this.order.vehicle.year}/${this.order.vehicle.make}`,
|
||||
payload: {},
|
||||
});
|
||||
},
|
||||
|
||||
// Vehicle API Actions
|
||||
updateVehicleYear(year)
|
||||
{
|
||||
|
|
@ -168,6 +184,20 @@ export const useMainStore = defineStore({
|
|||
}
|
||||
},
|
||||
|
||||
updateVehicleMake(make)
|
||||
{
|
||||
if (this.order.vehicle.make !== make) {
|
||||
this.order.vehicle.make = make;
|
||||
}
|
||||
},
|
||||
|
||||
updateVehicleModel(model)
|
||||
{
|
||||
if (this.order.vehicle.model !== model) {
|
||||
this.order.vehicle.model = model;
|
||||
}
|
||||
},
|
||||
|
||||
// populate initial state
|
||||
populateInitialState()
|
||||
{
|
||||
|
|
|
|||
6
src/styles/mixins/customMixins.scss
Normal file
6
src/styles/mixins/customMixins.scss
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
//Custom Mixins
|
||||
|
||||
//Blue gradient background mixin
|
||||
@mixin blue-gradient {
|
||||
background: linear-gradient(270deg, $blue 0%, $blue-800 100%);
|
||||
}
|
||||
|
|
@ -19,6 +19,7 @@ module.exports = {
|
|||
@import "@/styles/ux-variables.scss";
|
||||
@import "./node_modules/bootstrap/scss/variables";
|
||||
@import "./node_modules/bootstrap/scss/mixins";
|
||||
@import "@/styles/mixins/customMixins";
|
||||
`,
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -17,10 +17,11 @@ module.exports = {
|
|||
@import "@/styles/ux-variables.scss";
|
||||
@import "./node_modules/bootstrap/scss/variables";
|
||||
@import "./node_modules/bootstrap/scss/mixins";
|
||||
@import "@/styles/mixins/customMixins";
|
||||
`,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
configureWebpack: {
|
||||
devtool: 'source-map'
|
||||
},
|
||||
|
|
|
|||
Loading…
Reference in a new issue