Merge branch 'develop' into feature/CSR-74

This commit is contained in:
Max 2021-12-06 13:44:00 -05:00
commit b1685360ac
11 changed files with 53 additions and 222 deletions

View file

@ -1,144 +1,21 @@
import { shallowMount } from '@vue/test-utils';
import vehicleBanner from './vehicle-banner';
import { getMountOptions } from "@/helpers/unit-test-helper.js";
import { storeActions } from "@/constants/store-actions";
import { nextTick } from 'vue';
describe('vehicleBanner', () => {
const $store = {
state: {
order: {
vehicle: {
vin: null,
year: null,
make: null,
model: null,
style: null
}
}
}
};
const actionList = {
actionList: [
{
actionName: storeActions.LOOKUP_VEHICLE_BY_YMMS,
data: [
{
CarId: "CR00068434"
}
]
},
{
actionName: storeActions.LOOKUP_VEHICLE_BY_VIN,
data: [
{
CarId: "CR00068434"
}
]
},
{
actionName: storeActions.GET_EVOX_IMAGE,
data: {
imgSrc: "https://s3.amazonaws.com/safelite-lab-vehicle-images/Evox/8963_cc0320_032_UG_white_2014_Ford_Focus_18029225538399034889.jpg"
}
}
]
};
test('renders the blurrycar image when vehicleImageSrc is not present', () => {
test('renders the blurrycar image', () => {
// Arrange
const mountOptions = getMountOptions(actionList);
mountOptions.global.mocks = {
...mountOptions.global.mocks,
$store
}
// Act
const wrapper = shallowMount(vehicleBanner, {
...mountOptions
propsData: {
vehicleImageSrc: "image_url",
},
});
// Assert
expect(wrapper.find('img').attributes('class')).toContain('blurrycar');
wrapper.unmount();
});
test('does not render the blurrycar image when vehicleImageSrc exists', () => {
// Arrange
const mountOptions = getMountOptions(actionList);
mountOptions.global.mocks = {
...mountOptions.global.mocks,
$store
}
// Act
const wrapper = shallowMount(vehicleBanner, {
...mountOptions,
data() {
return {
vehicleImageSrc: "https://s3.amazonaws.com/safelite-lab-vehicle-images/Evox/8963_cc0320_032_UG_white_2014_Ford_Focus_18029225538399034889.jpg"
}
}
});
// Assert
expect(wrapper.find('img').attributes('class')).not.toContain('blurrycar');
wrapper.unmount();
});
test('does not render the blurrycar image when passedCarId is set', async () => {
// Arrange
const mountOptions = getMountOptions(actionList);
mountOptions.global.mocks = {
...mountOptions.global.mocks,
$store,
}
// Act
const wrapper = shallowMount(vehicleBanner, {
...mountOptions,
props: {
passedCarId: "CR00068434"
}
});
// Assert
await nextTick();
expect(wrapper.find('img').attributes('class')).not.toContain('blurrycar');
wrapper.unmount();
});
test('receives a carId when a YMMS object is found', async () => {
// Arrange
$store.state.order.vehicle.year = "2019"
$store.state.order.vehicle.make = "acura"
$store.state.order.vehicle.model = "rdx"
$store.state.order.vehicle.style = "4 door utility"
const mountOptions = getMountOptions(actionList);
mountOptions.global.mocks = {
...mountOptions.global.mocks,
$store
}
// Act
const wrapper = shallowMount(vehicleBanner, {
...mountOptions
});
// Assert
await nextTick();
expect(wrapper.vm.$data.carId.length).toBeGreaterThan(0);
wrapper.unmount();
});
test('receives a carId when a VIN is found', async () => {
// Arrange
$store.state.order.vehicle.vin = "1J4GW58S4XC541166";
const mountOptions = getMountOptions(actionList);
mountOptions.global.mocks = {
...mountOptions.global.mocks,
$store
}
// Act
const wrapper = shallowMount(vehicleBanner, {
...mountOptions
});
// Assert
await nextTick();
expect(wrapper.vm.$data.carId.length).toBeGreaterThan(0);
wrapper.unmount();
});
});

View file

@ -1,16 +1,9 @@
<template>
<div class="vehicle_banner mb-3 text-center">
<img
class="vehicle-image img-fluid"
:src="vehicleImageSrc"
v-if="vehicleImageSrc"
alt=""
/>
<img
class="vehicle-image img-fluid blurrycar"
:src="genericVehicleImageSrc"
:src="vehicleImageSrc"
alt=""
v-else
/>
</div>
</template>
@ -18,60 +11,12 @@
<script>
export default {
name: "vehicle-banner",
computed: {
vin () {
return this.$store.state.order.vehicle.vin;
},
ymms () {
return {
year: this.$store.state.order.vehicle.year,
make: this.$store.state.order.vehicle.make,
model: this.$store.state.order.vehicle.model,
style: this.$store.state.order.vehicle.style
};
},
},
props: {
passedCarId: String,
genericVehicleImageSrc: String
},
data() {
return {
years: [],
carId: '',
vehicleImageSrc: '',
};
},
created() {
if (this.passedCarId && this.passedCarId.length > 0) {
this.getVehicleImage(this.passedCarId)
} else if (this.vin && this.vin.length > 0) {
this.getCarIdWithVin(this.vin)
} else if (!Object.values(this.ymms).includes(null) && !Object.values(this.ymms).includes('')) {
this.getCarIdWithYmms(this.ymms)
vehicleImageSrc: {
type: String,
required: true
}
},
methods: {
getCarIdWithYmms(ymms) { // retrieve carId with YMMS object
this.dispatchNonBlockingStoreAction(this.storeActions.LOOKUP_VEHICLE_BY_YMMS, ymms).then((response) => {
this.carId = response.data[0].CarId;
this.getVehicleImage(this.carId)
});
},
getCarIdWithVin(vin) { // retrieve carId with VIN string
this.dispatchNonBlockingStoreAction(this.storeActions.LOOKUP_VEHICLE_BY_VIN, vin).then((response) => {
this.carId = response.data[0].CarId;
this.getVehicleImage(this.carId)
});
},
getVehicleImage(carId) { // look up evox with carId
this.dispatchNonBlockingStoreAction(this.storeActions.GET_EVOX_IMAGE, {relativeUrl: "https://mockey.qa.sagaws.net/service/evox-image?carId=" + carId}).then((response) => {
if (response.data && response.data.imgSrc) {
this.vehicleImageSrc = response.data.imgSrc;
}
});
},
},
}
</script>

View file

@ -155,11 +155,11 @@
</div>
<div class="row">
<!-- The role="radiogroup" and aria-labelledby must be included in the parent component for the radio group -->
<div role="radiogroup" aria-labelledby="demo-4-radio-group" class="col my-3 d-flex align-items-center flex-column">
<div role="radiogroup" aria-labelledby="demo-3-radio-group" class="col my-3 d-flex align-items-center flex-column">
<!-- The h3 and id must be included. The id must match the aria-labelledby of the parent div. -->
<h3 class="visually-hidden" id="demo-4-radio-group">Multi-Line Centered</h3>
<h3 class="visually-hidden" id="demo-3-radio-group">Multi-Line Centered</h3>
<radio
groupName="demo-4"
groupName="demo-3"
ariaLabelBy="vehicle-model"
radioID="Corvette"
radioLabelSubCopy="Test sub-headline"
@ -203,7 +203,7 @@
<radioHorizontal
groupName="demo-4"
ariaLabelBy="vehicle-model"
radioID="horizontal 1"
radioID="1"
radioLabelSubCopy=""
textPosition="text-center"
loaderColor="blue"
@ -215,7 +215,7 @@
<radioHorizontal
groupName="demo-4"
ariaLabelBy="vehicle-model"
radioID="horizontal-2"
radioID="2"
radioLabelSubCopy=""
textPosition="text-center"
loaderColor="blue"
@ -227,7 +227,7 @@
<radioHorizontal
groupName="demo-4"
ariaLabelBy="vehicle-model"
radioID="horizontal-3"
radioID="3"
radioLabelSubCopy=""
textPosition="text-center"
loaderColor="blue"
@ -367,8 +367,7 @@
</div>
<div class="row my-3">
<div class="col">
<vehicleBanner genericVehicleImageSrc="https://digitalconsumercms-dev.safelite.com/images/default-source/default-album/blurred-image.jpg?sfvrsn=a6ce3034_3" />
<vehicleBanner passedCarId="CR00068434" />
<vehicleBanner vehicleImageSrc="https://digitalconsumercms-dev.safelite.com/images/default-source/default-album/blurred-image.jpg?sfvrsn=a6ce3034_3" />
</div>
</div>
</div>

View file

@ -1,7 +1,7 @@
<template v-if="isCmsContentReady">
<div class="select-car">
<div class="select-car-form rounded text-center">
<vehicleBanner :genericVehicleImageSrc="vehicleBannerWidget.GenericVehicleImage" />
<vehicleBanner :vehicleImageSrc="vehicleBannerWidget.GenericVehicleImage" />
<pageHeader :text="pageHeaderWidgets.HeaderText" class="Header" />
<yearQuestion :questionText="radioQuestionWidgets.QuestionText" :years="vehicleYears" v-model="selectedYear" />
</div>

View file

@ -24,7 +24,7 @@ export default {
isDisabled: Boolean,
loaderColor: String,
loaderPosition: String,
sizeInRem: Number
sizeInRem: [Number,String]
},
data() {
return {

View file

@ -24,7 +24,7 @@ export default {
isDisabled: Boolean,
loaderColor: String,
loaderPosition: String,
sizeInRem: Number
sizeInRem: [Number,String]
},
data() {
return {

View file

@ -4,7 +4,6 @@
class="btn list-button d-flex align-items-center justify-content-between py-3 px-4"
@click='displayComponent'
v-bind:class="[
this.isLoading ? 'button-loader' : 'not-loading',
this.isError ? 'error' : '',
]"
>
@ -28,7 +27,7 @@ export default {
errorText: String,
loaderColor: String,
loaderPosition: String,
sizeInRem: Number
sizeInRem: [Number,String]
},
data() {
return {

View file

@ -27,6 +27,7 @@ describe("radio.vue", () => {
type: "radio",
value: "2023",
name: "TestGroup",
"aria-required": "true"
});
expect(label.attributes()).toEqual({

View file

@ -1,7 +1,15 @@
<!-- See the component-test.vue page for example implementation -->
<!-- role="radiogroup" and aria-labelledby must be included in the parent component for the radio group -->
<!-- Example: -->
<!-- <div role="radiogroup" aria-labelledby="demo-radio-group" class="col my-3 d-flex align-items-center flex-column"> -->
<!-- An h3 with id must be included just before the opening radio button group. ***The id must match the aria-labelledby of the parent div.*** -->
<!-- Example -->
<!-- <h3 class="visually-hidden" id="demo-radio-group">Select Vehicle Year</h3> -->
<template>
<!-- IMPORTANT: Refrain from using more than 4 horizontal radio buttons on desktop, 3 on mobile. -->
<div class="col radiogroup radio-horizontal d-flex flex-column mb-2">
<input type="radio" :id="radioID" :name="groupName" :value="radioID">
<label role="radio" tabindex="-1" aria-checked="false" :for="radioID" class="d-flex flex-column justify-content-center py-3 px-4" :class="isFirstOrLastItem" @click='displayComponent'>
<input type="radio" :id="radioID" :name="groupName" :value="radioID" aria-required="true"/>
<label role="radio" tabindex="-1" aria-checked="false" :for="radioID" class="d-flex flex-column justify-content-center py-3 px-4" :class="isFirstOrLastButton" @click='displayComponent'>
<span class="m-0" :class="[this.textPosition]">{{radioID}}</span>
<span class="m-0 small" :class="[this.textPosition]">{{radioLabelSubCopy}}</span>
<loader v-if="display" :style="{width: `${sizeInRem}rem`, height: `${sizeInRem}rem`}" :class="[this.loaderColor, this.loaderPosition]" />
@ -19,12 +27,12 @@ export default {
radioID: String, /* Required, unique for each radio button. Used for button id, label and <label for> */
radioLabelSubCopy: String, /* Optional, used for multi-line radio buttons */
textPosition: String, /* Optional, use Bootstrap classes: text-start, text-center, text-end. Default (empty) is text-start */
errorMessage: String, /* Optional */
loaderColor: String, /* Optional */
loaderPosition: String, /* Optional */
sizeInRem: String, /* Optional */
totalInGroup: Number,
positionInGroup: Number
errorMessage: String, /* Optional, if there is an error message to be displayed */
loaderColor: String, /* Specify color of loader/spinner. Options are blue, red, green, white, black. Default is blue */
loaderPosition: String, /* Specify horizontal position of loader/spinner. Options are center, right, left */
sizeInRem: [Number,String], /* Specify size of loader/spinner in rem. Example: 1.5 (equals 24px (16x1.5)) */
totalInGroup: Number, /* Required, total number of radio buttons in group. Used to tell first and last in group to apply border radius. */
positionInGroup: Number /* Rquired, position of radio button in group. Example, 1,2,3 */
},
data() {
return {
@ -35,13 +43,13 @@ export default {
methods: {
displayComponent() {
this.display = true;
},
}
},
components: {
loader,
},
computed: {
isFirstOrLastItem() {
isFirstOrLastButton() {
let className = '';
if(this.positionInGroup == this.totalInGroup) {
className = 'last-item'
@ -82,6 +90,7 @@ export default {
&:hover {
box-shadow: 0 0 0 4px $blue-100;
cursor: pointer;
z-index: 2;
}
+ p {
display: none;

View file

@ -27,6 +27,7 @@ describe("radio.vue", () => {
type: "radio",
value: "2023",
name: "TestGroup",
"aria-required": "true"
});
expect(label.attributes()).toEqual({

View file

@ -7,7 +7,7 @@
<!-- Example -->
<!-- <h3 class="visually-hidden" id="demo-radio-group">Select Vehicle Year</h3> -->
<div class="radiogroup radio-list-button d-flex flex-column w-100 mb-2">
<input type="radio" :id="radioID" :name="groupName" :value="radioID">
<input type="radio" :id="radioID" :name="groupName" :value="radioID" aria-required="true">
<label role="radio" tabindex="-1" aria-checked="false" :for="radioID" class="d-flex flex-column justify-content-center py-3 px-4" @click='displayComponent'>
<span class="m-0" :class="[this.textPosition]">{{radioID}}</span>
<span class="m-0 small" :class="[this.textPosition]">{{radioLabelSubCopy}}</span>
@ -21,16 +21,16 @@
import loader from "@/ux-components/loader/loader";
export default {
name: "radioList",
props: [
"groupName", /* Required, unique for each radio button GROUP */
"radioID", /* Required, unique for each radio button. Used for button id, label and <label for> */
"radioLabelSubCopy", /* Optional, used for multi-line radio buttons */
"textPosition", /* Optional, use Bootstrap classes: text-start, text-center, text-end. Default (empty) is text-start */
"errorMessage", /* Optional */
"loaderColor", /* Optional */
"loaderPosition", /* Optional */
"sizeInRem" /* Optional */
],
props: {
groupName: String, /* Required, unique for each radio button GROUP */
radioID: String, /* Required, unique for each radio button. Used for button id, label and <label for> */
radioLabelSubCopy: String, /* Optional, used for multi-line radio buttons */
textPosition: String, /* Optional, use Bootstrap classes: text-start, text-center, text-end. Default (empty) is text-start */
errorMessage: String, /* Optional, if there is an error message to be displayed */
loaderColor: String, /* Specify color of loader/spinner. Options are blue, red, green, white, black. Default is blue */
loaderPosition: String, /* Specify horizontal position of loader/spinner. Options are center, right, left */
sizeInRem: [Number,String], /* Specify size of loader/spinner in rem. Example: 1.5 (equals 24px (16x1.5)) */
},
data() {
return {
isError: false,