Merge branch 'feature/CSR-6' into feature/CSR-121_button-click-function
This commit is contained in:
commit
09396149c5
15 changed files with 223 additions and 212 deletions
|
|
@ -2,6 +2,7 @@ import { shallowMount } from '@vue/test-utils';
|
||||||
import vehicleBanner from './vehicle-banner';
|
import vehicleBanner from './vehicle-banner';
|
||||||
import { getMountOptions } from "@/helpers/unit-test-helper.js";
|
import { getMountOptions } from "@/helpers/unit-test-helper.js";
|
||||||
import { storeActions } from "@/constants/store-actions";
|
import { storeActions } from "@/constants/store-actions";
|
||||||
|
import { nextTick } from 'vue';
|
||||||
|
|
||||||
describe('vehicleBanner', () => {
|
describe('vehicleBanner', () => {
|
||||||
const $store = {
|
const $store = {
|
||||||
|
|
@ -44,7 +45,7 @@ describe('vehicleBanner', () => {
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
test('renders the blurrycar image when vehicleImageSrc is not present', async () => {
|
test('renders the blurrycar image when vehicleImageSrc is not present', () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const mountOptions = getMountOptions(actionList);
|
const mountOptions = getMountOptions(actionList);
|
||||||
mountOptions.global.mocks = {
|
mountOptions.global.mocks = {
|
||||||
|
|
@ -60,7 +61,7 @@ describe('vehicleBanner', () => {
|
||||||
wrapper.unmount();
|
wrapper.unmount();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('does not render the blurrycar image when vehicleImageSrc exists', async () => {
|
test('does not render the blurrycar image when vehicleImageSrc exists', () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const mountOptions = getMountOptions(actionList);
|
const mountOptions = getMountOptions(actionList);
|
||||||
mountOptions.global.mocks = {
|
mountOptions.global.mocks = {
|
||||||
|
|
@ -77,9 +78,7 @@ describe('vehicleBanner', () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// Assert
|
// Assert
|
||||||
setTimeout(() => {
|
expect(wrapper.find('img').attributes('class')).not.toContain('blurrycar');
|
||||||
expect(wrapper.find('img').attributes('class')).not.toContain('blurrycar');
|
|
||||||
}, 500);
|
|
||||||
wrapper.unmount();
|
wrapper.unmount();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -98,13 +97,12 @@ describe('vehicleBanner', () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// Assert
|
// Assert
|
||||||
setTimeout(() => {
|
await nextTick();
|
||||||
expect(wrapper.find('img').attributes('class')).not.toContain('blurrycar');
|
expect(wrapper.find('img').attributes('class')).not.toContain('blurrycar');
|
||||||
}, 500);
|
|
||||||
wrapper.unmount();
|
wrapper.unmount();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('does not render the blurrycar image when a YMMS object is found', async () => {
|
test('receives a carId when a YMMS object is found', async () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
$store.state.order.vehicle.year = "2019"
|
$store.state.order.vehicle.year = "2019"
|
||||||
$store.state.order.vehicle.make = "acura"
|
$store.state.order.vehicle.make = "acura"
|
||||||
|
|
@ -120,14 +118,12 @@ describe('vehicleBanner', () => {
|
||||||
...mountOptions
|
...mountOptions
|
||||||
});
|
});
|
||||||
// Assert
|
// Assert
|
||||||
setTimeout(() => {
|
await nextTick();
|
||||||
expect(wrapper.find('img').attributes('class')).not.toContain('blurrycar');
|
expect(wrapper.vm.$data.carId.length).toBeGreaterThan(0);
|
||||||
}, 500);
|
|
||||||
wrapper.unmount();
|
wrapper.unmount();
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('does not render the blurrycar image when a VIN is found', async () => {
|
test('receives a carId when a VIN is found', async () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
$store.state.order.vehicle.vin = "1J4GW58S4XC541166";
|
$store.state.order.vehicle.vin = "1J4GW58S4XC541166";
|
||||||
const mountOptions = getMountOptions(actionList);
|
const mountOptions = getMountOptions(actionList);
|
||||||
|
|
@ -140,9 +136,9 @@ describe('vehicleBanner', () => {
|
||||||
...mountOptions
|
...mountOptions
|
||||||
});
|
});
|
||||||
// Assert
|
// Assert
|
||||||
setTimeout(() => {
|
await nextTick();
|
||||||
expect(wrapper.find('img').attributes('class')).not.toContain('blurrycar');
|
expect(wrapper.vm.$data.carId.length).toBeGreaterThan(0);
|
||||||
}, 500);
|
|
||||||
wrapper.unmount();
|
wrapper.unmount();
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="vehicle_banner mb-3">
|
<div class="vehicle_banner mb-3 text-center">
|
||||||
<img
|
<img
|
||||||
class="vehicle-image img-fluid"
|
class="vehicle-image img-fluid"
|
||||||
:src="vehicleImageSrc"
|
:src="vehicleImageSrc"
|
||||||
|
|
@ -53,14 +53,14 @@ export default {
|
||||||
methods: {
|
methods: {
|
||||||
getCarIdWithYmms(ymms) { // retrieve carId with YMMS object
|
getCarIdWithYmms(ymms) { // retrieve carId with YMMS object
|
||||||
this.dispatchNonBlockingStoreAction(this.storeActions.LOOKUP_VEHICLE_BY_YMMS, ymms).then((response) => {
|
this.dispatchNonBlockingStoreAction(this.storeActions.LOOKUP_VEHICLE_BY_YMMS, ymms).then((response) => {
|
||||||
const carId = response.data[0].CarId;
|
this.carId = response.data[0].CarId;
|
||||||
this.getVehicleImage(carId)
|
this.getVehicleImage(this.carId)
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
getCarIdWithVin(vin) { // retrieve carId with VIN string
|
getCarIdWithVin(vin) { // retrieve carId with VIN string
|
||||||
this.dispatchNonBlockingStoreAction(this.storeActions.LOOKUP_VEHICLE_BY_VIN, vin).then((response) => {
|
this.dispatchNonBlockingStoreAction(this.storeActions.LOOKUP_VEHICLE_BY_VIN, vin).then((response) => {
|
||||||
const carId = response.data[0].CarId;
|
this.carId = response.data[0].CarId;
|
||||||
this.getVehicleImage(carId)
|
this.getVehicleImage(this.carId)
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
getVehicleImage(carId) { // look up evox with carId
|
getVehicleImage(carId) { // look up evox with carId
|
||||||
|
|
|
||||||
30
src/helpers/cms-content-helper.js
Normal file
30
src/helpers/cms-content-helper.js
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
import { storeActions } from "@/constants/store-actions.js";
|
||||||
|
import { widgetNames } from "@/constants/widget-names.js";
|
||||||
|
import store from "@/store";
|
||||||
|
|
||||||
|
export function fetchCmsContentForPage(fmgPage) {
|
||||||
|
return store.dispatch(storeActions.GET_PAGE_DATA, { pageName: fmgPage }).then((response) => {
|
||||||
|
|
||||||
|
const pageDataFromCms = {
|
||||||
|
isCmsContentReady: false
|
||||||
|
};
|
||||||
|
|
||||||
|
response.data.Result.forEach((widget) => {
|
||||||
|
if (Object.values(widgetNames).includes(widget.Type)) {
|
||||||
|
// If we already have this widget, push it on the collection
|
||||||
|
if (widget.Type in pageDataFromCms) {
|
||||||
|
pageDataFromCms[widget.Type].push(widget.Model);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pageDataFromCms[widget.Type] = [widget.Model];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Our 'Page' is ready because we have data now
|
||||||
|
pageDataFromCms.isCmsContentReady = true;
|
||||||
|
|
||||||
|
return pageDataFromCms;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
29
src/helpers/layout-helper.js
Normal file
29
src/helpers/layout-helper.js
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
export function settleAllPromises(layoutPromiseTable) {
|
||||||
|
|
||||||
|
// Pull our keys out of the promise 'table'
|
||||||
|
const promiseNames = Object.entries(layoutPromiseTable);
|
||||||
|
|
||||||
|
return Promise.allSettled(promiseNames.map(e => e[1]).map(n => n.promise))
|
||||||
|
.then(results => {
|
||||||
|
|
||||||
|
const resultMap = {};
|
||||||
|
|
||||||
|
// Build a map of the results
|
||||||
|
for (let i = 0; i < results.length; ++i) {
|
||||||
|
|
||||||
|
const promiseName = promiseNames[i][1].key;
|
||||||
|
|
||||||
|
// Some Promises like the cms content call don't have a 'data' field
|
||||||
|
// when returned, so other promises do. Map the results to the object
|
||||||
|
// so that the object is the return data.
|
||||||
|
|
||||||
|
if (results[i].value.data === undefined) {
|
||||||
|
resultMap[promiseName] = results[i].value
|
||||||
|
} else {
|
||||||
|
resultMap[promiseName] = results[i].value.data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultMap;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { storeActions } from "@/constants/store-actions";
|
import { storeActions } from "@/constants/store-actions";
|
||||||
import store from "@/store";
|
import store from "@/store";
|
||||||
|
|
||||||
export function getMountOptions(mockData, cmsMockData = null) {
|
export function getMountOptions(mockData) {
|
||||||
// Define our mocks to attached to the 'global' object for Vue/Jest.
|
// Define our mocks to attached to the 'global' object for Vue/Jest.
|
||||||
const mocks = {};
|
const mocks = {};
|
||||||
|
|
||||||
|
|
@ -18,16 +18,9 @@ export function getMountOptions(mockData, cmsMockData = null) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if(cmsMockData){
|
|
||||||
mocks.GetContentFromCms = jest.fn();
|
|
||||||
mocks.GetContentFromCms.mockImplementation(() =>
|
|
||||||
{
|
|
||||||
return cmsMockData;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mock store actions from js file
|
// Mock store actions from js file
|
||||||
mocks.storeActions = storeActions;
|
mocks.storeActions = storeActions;
|
||||||
|
|
||||||
const global = {
|
const global = {
|
||||||
mocks: mocks,
|
mocks: mocks,
|
||||||
plugins: [store]
|
plugins: [store]
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,9 @@
|
||||||
<div class="col my-3 d-flex align-items-center">
|
<div class="col my-3 d-flex align-items-center">
|
||||||
<buttonPrimary
|
<buttonPrimary
|
||||||
buttonText="Primary"
|
buttonText="Primary"
|
||||||
|
loaderColor="white"
|
||||||
|
loaderPosition="right"
|
||||||
|
sizeInRem="1"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -44,6 +47,9 @@
|
||||||
<div class="col my-3 d-flex align-items-center">
|
<div class="col my-3 d-flex align-items-center">
|
||||||
<buttonSecondary
|
<buttonSecondary
|
||||||
buttonText="Secondary"
|
buttonText="Secondary"
|
||||||
|
loaderColor="white"
|
||||||
|
loaderPosition="right"
|
||||||
|
sizeInRem="1"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -227,7 +233,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row my-3">
|
<div class="row my-3">
|
||||||
<div class="d-flex align-items-center">
|
<div class="col">
|
||||||
<vehicleBanner
|
<vehicleBanner
|
||||||
passedCarId=""
|
passedCarId=""
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -1,27 +1,56 @@
|
||||||
import { shallowMount, flushPromises } from "@vue/test-utils";
|
import { shallowMount, flushPromises } from "@vue/test-utils";
|
||||||
import { getMountOptions } from "@/helpers/unit-test-helper.js";
|
import { getMountOptions } from "@/helpers/unit-test-helper.js";
|
||||||
import vehicleYear from "@/layouts/vehicle-year/vehicle-year.vue";
|
import vehicleYear from "@/layouts/vehicle-year/vehicle-year.vue";
|
||||||
|
import { settleAllPromises } from "@/helpers/layout-helper.js";
|
||||||
|
import { nextTick } from 'vue'
|
||||||
|
|
||||||
|
// Mock our module for promises.
|
||||||
|
jest.mock("@/helpers/layout-helper.js", () => ({
|
||||||
|
settleAllPromises: jest.fn()
|
||||||
|
}));
|
||||||
|
|
||||||
describe("vehicle-year.vue", () => {
|
describe("vehicle-year.vue", () => {
|
||||||
test("vehicle-year.vue should render data from CMS", async () => {
|
test("vehicle-year.vue should render data from CMS", async () => {
|
||||||
|
|
||||||
// Arrange
|
// Arrange
|
||||||
const cmsMockData = {
|
|
||||||
PageHeaderWidget: [{ HeaderText: "Select a year to get started" }],
|
// Our mock data for our call to settleAllPromises
|
||||||
RadioQuestionWidget: [{ QuestionText: "What year is your vehicle?" }],
|
const mockData = {
|
||||||
|
getPageContent: {
|
||||||
|
PageHeaderWidget: [{ HeaderText: "Select a year to get started" }],
|
||||||
|
RadioQuestionWidget: [{ QuestionText: "What year is your vehicle?" }],
|
||||||
|
isCmsContentReady: true,
|
||||||
|
},
|
||||||
|
getVehicleYear: [2023, 2022, 2021]
|
||||||
}
|
}
|
||||||
|
|
||||||
const mountOptions = getMountOptions({}, cmsMockData);
|
// our router information needed.
|
||||||
|
const to = {
|
||||||
|
query: {
|
||||||
|
fmgPage: 'vehicle-year'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const mountOptions = getMountOptions(mockData);
|
||||||
|
|
||||||
|
// our mock implementation of settleAllPromises
|
||||||
|
settleAllPromises.mockImplementation(() => { return Promise.resolve(mockData);});
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
const wrapper = shallowMount(vehicleYear, mountOptions);
|
const wrapper = shallowMount(vehicleYear, mountOptions);
|
||||||
await flushPromises();
|
|
||||||
|
// Call our beforeRouteEnter on the component.
|
||||||
|
// This passes (c) => c(wrapper.vm) so that next can be called and our
|
||||||
|
// data can be set.
|
||||||
|
vehicleYear.beforeRouteEnter.call(wrapper.vm, to, undefined, (c) => c(wrapper.vm));
|
||||||
|
|
||||||
|
await nextTick(); // Wait for the DOM to update.
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
const header = await wrapper.find(".Header");
|
const header = await wrapper.find(".Header");
|
||||||
expect(header.attributes("text")).toEqual("Select a year to get started");
|
expect(header.attributes("text")).toEqual("Select a year to get started");
|
||||||
|
|
||||||
const yearQuestion = await wrapper.findComponent({name: 'year-question'});
|
const yearQuestion = wrapper.findComponent({ name: 'year-question' });
|
||||||
expect(yearQuestion.attributes("questiontext")).toEqual("What year is your vehicle?");
|
expect(yearQuestion.attributes("questiontext")).toEqual("What year is your vehicle?");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,37 +1,62 @@
|
||||||
<template v-if="isCmsContentReady">
|
<template>
|
||||||
<div class="select-car">
|
<div class="select-car">
|
||||||
<div class="select-car-form rounded text-center">
|
<div class="select-car-form rounded text-center">
|
||||||
<vehicleBanner />
|
<pageHeader :text="pageHeaderWidgets.HeaderText" class="Header" />
|
||||||
<pageHeader :text="pageHeaderWidgets.HeaderText" class="Header" />
|
<yearQuestion :questionText="radioQuestionWidgets.QuestionText" :years="vehicleYears" />
|
||||||
<yearQuestion :questionText="radioQuestionWidgets.QuestionText" />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import yearQuestion from "@/layouts/vehicle-year/year-question/year-question";
|
import yearQuestion from "@/layouts/vehicle-year/year-question/year-question";
|
||||||
import pageHeader from "@/ux-components/header/header";
|
import pageHeader from "@/ux-components/header/header";
|
||||||
import vehicleBanner from "@/common-components/vehicle-banner/vehicle-banner";
|
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
|
||||||
|
import { settleAllPromises } from "@/helpers/layout-helper";
|
||||||
|
import store from "@/store";
|
||||||
|
import { storeActions } from "@/constants/store-actions.js";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "vehicle-year",
|
name: "vehicle-year",
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
pageHeaderWidgets: {},
|
pageHeaderWidgets: {},
|
||||||
radioQuestionWidgets: {},
|
radioQuestionWidgets: {},
|
||||||
};
|
vehicleYears: [],
|
||||||
},
|
};
|
||||||
async created() {
|
},
|
||||||
const pageContent = await this.GetContentFromCms();
|
computed: {},
|
||||||
|
beforeRouteEnter(to, from, next) {
|
||||||
|
|
||||||
this.pageHeaderWidgets = pageContent.PageHeaderWidget[0];
|
const contentPromise = fetchCmsContentForPage(to.query.fmgPage);
|
||||||
this.radioQuestionWidgets = pageContent.RadioQuestionWidget[0];
|
const getVehicleYearPromise = store.dispatch(storeActions.GET_VEHICLE_YEARS, {});
|
||||||
},
|
|
||||||
components: {
|
const promiseResultMap = [
|
||||||
yearQuestion,
|
{
|
||||||
pageHeader,
|
resultKey: "getPageContent",
|
||||||
vehicleBanner,
|
promise: contentPromise,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
resultKey: "getVehicleYear",
|
||||||
|
promise: getVehicleYearPromise,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
settleAllPromises(promiseResultMap).then((resultMap) => {
|
||||||
|
|
||||||
|
// Call our next function to transition to the next page.
|
||||||
|
next((vm) => {
|
||||||
|
vm.pageHeaderWidgets = resultMap.getPageContent.PageHeaderWidget[0];
|
||||||
|
vm.radioQuestionWidgets = resultMap.getPageContent.RadioQuestionWidget[0];
|
||||||
|
vm.vehicleYears = resultMap.getVehicleYear;
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
yearQuestion,
|
||||||
|
pageHeader,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,16 +13,9 @@ export default {
|
||||||
name: "year-question",
|
name: "year-question",
|
||||||
props: {
|
props: {
|
||||||
questionText: String,
|
questionText: String,
|
||||||
},
|
years: Array
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
years: [],
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.dispatchNonBlockingStoreAction(this.storeActions.GET_VEHICLE_YEARS, {}).then((response) => {
|
|
||||||
this.years = response.data;
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
radioQuestion,
|
radioQuestion,
|
||||||
|
|
|
||||||
|
|
@ -24,12 +24,11 @@ export default {
|
||||||
|
|
||||||
return this.$store.dispatch(type, payload);
|
return this.$store.dispatch(type, payload);
|
||||||
},
|
},
|
||||||
|
|
||||||
GetContentFromCms() {
|
GetContentFromCms() {
|
||||||
return this.dispatchNonBlockingStoreAction(this.storeActions.GET_PAGE_DATA,{ pageName: this.$route.query.fmgPage }).then((response) => {
|
return this.dispatchNonBlockingStoreAction(this.storeActions.GET_PAGE_DATA,{ pageName: this.$route.query.fmgPage }).then((response) => {
|
||||||
|
|
||||||
const pageDataFromCms = {};
|
const pageDataFromCms = {};
|
||||||
|
|
||||||
response.data.Result.forEach((widget) => {
|
response.data.Result.forEach((widget) => {
|
||||||
if (Object.values(this.widgetNames).includes(widget.Type)) {
|
if (Object.values(this.widgetNames).includes(widget.Type)) {
|
||||||
// If we already have this widget, push it on the collection
|
// If we already have this widget, push it on the collection
|
||||||
|
|
@ -39,10 +38,10 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
pageDataFromCms[widget.Type] = [widget.Model];
|
pageDataFromCms[widget.Type] = [widget.Model];
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Our 'Page' is ready because we have data now
|
// Our 'Page' is ready because we have data now
|
||||||
this.isCmsContentReady = true;
|
this.isCmsContentReady = true;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,60 +23,6 @@ describe("baseMixin.js", () => {
|
||||||
|
|
||||||
expect(mixIn.methods.$store.dispatch).toBeCalledWith(type, payload);
|
expect(mixIn.methods.$store.dispatch).toBeCalledWith(type, payload);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GetContentFromCms: Should return mapped data and call dispatchNonblockingStoreAction', async () => {
|
|
||||||
const mixIn = getMixInInstance({});
|
|
||||||
|
|
||||||
// Mock dispatch action
|
|
||||||
mixIn.methods.dispatchNonBlockingStoreAction = jest.fn();
|
|
||||||
mixIn.methods.dispatchNonBlockingStoreAction.mockImplementation((action) => {
|
|
||||||
if (action === 'getPageData') {
|
|
||||||
return Promise.resolve({
|
|
||||||
data: {
|
|
||||||
Result: [
|
|
||||||
{
|
|
||||||
Type: "PageConfigWidget",
|
|
||||||
Model: {
|
|
||||||
LayoutNames: [
|
|
||||||
"None",
|
|
||||||
"vehicle-year"
|
|
||||||
],
|
|
||||||
LayoutStyle: "vehicle-year"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Type: "RadioQuestionWidget",
|
|
||||||
Model: {
|
|
||||||
"QuestionText": "What year is your vehicle?"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Type: "RadioQuestionWidget",
|
|
||||||
Model: {
|
|
||||||
"QuestionText": "This is a second radio question"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Type: "PageHeaderWidget",
|
|
||||||
Model: {
|
|
||||||
"HeaderText": "Select a year to get started"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const result = await mixIn.methods.GetContentFromCms();
|
|
||||||
await flushPromises();
|
|
||||||
|
|
||||||
|
|
||||||
expect(mixIn.methods.dispatchNonBlockingStoreAction).toBeCalledWith(storeActions.GET_PAGE_DATA, { pageName: 'test-page'});
|
|
||||||
|
|
||||||
expect(result.PageHeaderWidget[0].HeaderText).toEqual('Select a year to get started');
|
|
||||||
|
|
||||||
});
|
|
||||||
})
|
})
|
||||||
function getMixInInstance({ isDispatchSuccess = true }) {
|
function getMixInInstance({ isDispatchSuccess = true }) {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,23 +16,8 @@
|
||||||
&:focus-visible { // Keyboard focus for accessibility
|
&:focus-visible { // Keyboard focus for accessibility
|
||||||
outline: none;
|
outline: none;
|
||||||
box-shadow: 0 0 0 3px, 0 0 0 5.5px $blue-700;
|
box-shadow: 0 0 0 3px, 0 0 0 5.5px $blue-700;
|
||||||
}
|
color: $white;
|
||||||
&.button-loader {
|
@include blue-gradient;
|
||||||
padding: 0 40px 0 12px;
|
|
||||||
&:after {
|
|
||||||
content: url(../../assets/img/icons/button-spinner-white.svg);
|
|
||||||
position: absolute;
|
|
||||||
right: 14px;
|
|
||||||
width: 16px;
|
|
||||||
height: 16px;
|
|
||||||
margin-left: 12px;
|
|
||||||
animation: rotation 1s infinite linear;
|
|
||||||
@keyframes rotation {
|
|
||||||
100% {
|
|
||||||
transform:rotate(360deg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
&:disabled {
|
&:disabled {
|
||||||
background: $gray-100 !important;
|
background: $gray-100 !important;
|
||||||
|
|
@ -59,39 +44,8 @@
|
||||||
&:focus-visible { // Keyboard focus for accessibility
|
&:focus-visible { // Keyboard focus for accessibility
|
||||||
outline: none;
|
outline: none;
|
||||||
box-shadow: 0 0 0 3px $white, 0 0 0 5.5px $blue-700;
|
box-shadow: 0 0 0 3px $white, 0 0 0 5.5px $blue-700;
|
||||||
}
|
color: $white;
|
||||||
&.button-loader {
|
@include blue-gradient;
|
||||||
padding: 0 40px 0 12px;
|
|
||||||
&:after {
|
|
||||||
content: url(../../assets/img/icons/button-spinner-blue.svg);
|
|
||||||
position: absolute;
|
|
||||||
right: 14px;
|
|
||||||
width: 16px;
|
|
||||||
height: 16px;
|
|
||||||
margin-left: 12px;
|
|
||||||
animation: rotation 1s infinite linear;
|
|
||||||
@keyframes rotation {
|
|
||||||
100% {
|
|
||||||
transform:rotate(360deg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&:focus:hover {
|
|
||||||
&:after {
|
|
||||||
content: url(../../assets/img/icons/button-spinner-white.svg);
|
|
||||||
position: absolute;
|
|
||||||
right: 14px;
|
|
||||||
width: 16px;
|
|
||||||
height: 16px;
|
|
||||||
margin-left: 12px;
|
|
||||||
animation: rotation 1s infinite linear;
|
|
||||||
@keyframes rotation {
|
|
||||||
100% {
|
|
||||||
transform:rotate(360deg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
&:disabled {
|
&:disabled {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
|
|
@ -130,22 +84,5 @@
|
||||||
color: $danger;
|
color: $danger;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&.button-loader {
|
|
||||||
padding: 0 40px 0 12px;
|
|
||||||
&:after {
|
|
||||||
content: url(../../assets/img/icons/button-spinner-blue.svg);
|
|
||||||
position: absolute;
|
|
||||||
right: 14px;
|
|
||||||
width: 16px;
|
|
||||||
height: 16px;
|
|
||||||
margin-left: 12px;
|
|
||||||
animation: rotation 1s infinite linear;
|
|
||||||
@keyframes rotation {
|
|
||||||
100% {
|
|
||||||
transform:rotate(360deg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="alert fade show text-center mb-0" role="alert"
|
<div class="alert fade show text-center mb-0 py-2 px-3" role="alert"
|
||||||
:class="[ isDismissible ? 'alert-dismissible' : '', this.alertClass ]"
|
:class="[ isDismissible ? 'alert-dismissible' : '', this.alertClass ]"
|
||||||
>
|
>
|
||||||
<p class="m-0 fw-bold small alert-heading">{{alertHeadline}}</p>
|
<p class="m-0 fw-bold small alert-heading">{{alertHeadline}}</p>
|
||||||
<p class="m-0 text-body small">{{alertCopy}}</p>
|
<p class="m-0 text-body small">{{alertCopy}}</p>
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close">
|
<button type="button" class="btn-close p-2" data-bs-dismiss="alert" aria-label="Close">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 23.7 23.7" xml:space="preserve">
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 23.7 23.7" xml:space="preserve">
|
||||||
<path d="m23.24 2.7-9.15 9.15L23.24 21a1.581 1.581 0 0 1-1.12 2.7c-.42 0-.82-.16-1.12-.46l-9.15-9.15-9.15 9.15c-.3.3-.7.46-1.12.46A1.581 1.581 0 0 1 .46 21l8.47-8.47.68-.68L.46 2.7c-.62-.62-.62-1.62 0-2.24.62-.62 1.62-.62 2.24 0l8.47 8.47.68.68L21 .46a1.57 1.57 0 0 1 2.23 0c.63.62.63 1.62.01 2.24z"/>
|
<path d="m23.24 2.7-9.15 9.15L23.24 21a1.581 1.581 0 0 1-1.12 2.7c-.42 0-.82-.16-1.12-.46l-9.15-9.15-9.15 9.15c-.3.3-.7.46-1.12.46A1.581 1.581 0 0 1 .46 21l8.47-8.47.68-.68L.46 2.7c-.62-.62-.62-1.62 0-2.24.62-.62 1.62-.62 2.24 0l8.47 8.47.68.68L21 .46a1.57 1.57 0 0 1 2.23 0c.63.62.63 1.62.01 2.24z"/>
|
||||||
</svg>
|
</svg>
|
||||||
|
|
@ -39,10 +39,14 @@ export default {
|
||||||
.btn-close {
|
.btn-close {
|
||||||
background: none;
|
background: none;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
|
width: .75rem;
|
||||||
|
height: .75rem;
|
||||||
}
|
}
|
||||||
&.alert-dismissible {
|
&.alert-dismissible {
|
||||||
button {
|
button {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
top: 2px;
|
||||||
|
right: 2px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&.alert-info {
|
&.alert-info {
|
||||||
|
|
|
||||||
|
|
@ -3,29 +3,41 @@
|
||||||
:disabled="isDisabled"
|
:disabled="isDisabled"
|
||||||
:aria-disabled="isDisabled"
|
:aria-disabled="isDisabled"
|
||||||
class="btn btn-primary d-flex align-items-center"
|
class="btn btn-primary d-flex align-items-center"
|
||||||
v-on:click="showLoader()"
|
@click='displayComponent'
|
||||||
v-bind:class="[this.isLoading ? 'button-loader' : 'not-loading']"
|
>
|
||||||
>
|
|
||||||
{{ this.buttonText }}
|
{{ this.buttonText }}
|
||||||
|
<loader
|
||||||
|
class="ms-2"
|
||||||
|
v-if="display"
|
||||||
|
v-bind:style="{width: `${sizeInRem}rem`, height: `${sizeInRem}rem`}"
|
||||||
|
v-bind:class="[this.loaderColor, this.loaderPosition]"
|
||||||
|
/>
|
||||||
</button>
|
</button>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import loader from "@/ux-components/loader/loader";
|
||||||
export default {
|
export default {
|
||||||
name: "buttonPrimary",
|
name: "buttonPrimary",
|
||||||
props: {
|
props: {
|
||||||
buttonText: String,
|
buttonText: String,
|
||||||
isDisabled: Boolean,
|
isDisabled: Boolean,
|
||||||
|
loaderColor: String,
|
||||||
|
loaderPosition: String,
|
||||||
|
sizeInRem: Number
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
isLoading: false,
|
display: false,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
showLoader() {
|
displayComponent() {
|
||||||
this.isLoading = true;
|
this.display = true;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
components: {
|
||||||
|
loader,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -3,29 +3,41 @@
|
||||||
:disabled="isDisabled"
|
:disabled="isDisabled"
|
||||||
:aria-disabled="isDisabled"
|
:aria-disabled="isDisabled"
|
||||||
class="btn btn-secondary d-flex align-items-center"
|
class="btn btn-secondary d-flex align-items-center"
|
||||||
v-on:click="showLoader()"
|
@click='displayComponent'
|
||||||
v-bind:class="[this.isLoading ? 'button-loader' : 'not-loading']"
|
>
|
||||||
>
|
|
||||||
{{ this.buttonText }}
|
{{ this.buttonText }}
|
||||||
|
<loader
|
||||||
|
class="ms-2"
|
||||||
|
v-if="display"
|
||||||
|
v-bind:style="{width: `${sizeInRem}rem`, height: `${sizeInRem}rem`}"
|
||||||
|
v-bind:class="[this.loaderColor, this.loaderPosition]"
|
||||||
|
/>
|
||||||
</button>
|
</button>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import loader from "@/ux-components/loader/loader";
|
||||||
export default {
|
export default {
|
||||||
name: "buttonSecondary",
|
name: "buttonPrimary",
|
||||||
props: {
|
props: {
|
||||||
buttonText: String,
|
buttonText: String,
|
||||||
|
isDisabled: Boolean,
|
||||||
|
loaderColor: String,
|
||||||
|
loaderPosition: String,
|
||||||
|
sizeInRem: Number
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
isLoading: false,
|
display: false,
|
||||||
isDisabled: false,
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
showLoader() {
|
displayComponent() {
|
||||||
this.isLoading = true;
|
this.display = true;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
components: {
|
||||||
|
loader,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue