Adding replace options component and unit tests
This commit is contained in:
parent
ceec84f168
commit
221b5c1e73
9 changed files with 294 additions and 30 deletions
|
|
@ -21,3 +21,80 @@ describe("buttonQuestion.vue", () => {
|
|||
expect(wrapper.props().modelValue).toBe("2020");
|
||||
});
|
||||
});
|
||||
|
||||
describe("buttonQuestion.vue", () => {
|
||||
it("Should show overflow classes on fieldset if isOverflowScrollable is true", async () => {
|
||||
// Act
|
||||
const wrapper = shallowMount(buttonQuestion);
|
||||
await wrapper.setProps({
|
||||
isOverflowScrollable: true,
|
||||
});
|
||||
// Assert
|
||||
const fieldSet = wrapper.find('fieldset');
|
||||
expect(fieldSet.classes()).toContain("overflow-scroll");
|
||||
});
|
||||
});
|
||||
|
||||
describe("buttonQuestion.vue", () => {
|
||||
it("Should show appropriate classes for button type", async () => {
|
||||
// Act
|
||||
const wrapper = shallowMount(buttonQuestion);
|
||||
await wrapper.setProps({
|
||||
buttonType: "listCard",
|
||||
});
|
||||
// Assert
|
||||
const Div = wrapper.find('fieldset div');
|
||||
expect(Div.classes()).toContain("row");
|
||||
});
|
||||
});
|
||||
|
||||
describe("buttonQuestion.vue", () => {
|
||||
it("Should trigger event modelValue change on select", async () => {
|
||||
// Act
|
||||
const wrapper = shallowMount(buttonQuestion);
|
||||
await wrapper.setData({
|
||||
modelValueAnswers: ["Windshield"],
|
||||
chosenAnswer: "Windshield"
|
||||
});
|
||||
wrapper.setValue({ answer: wrapper.vm.chosenAnswer });
|
||||
await wrapper.vm.$nextTick();
|
||||
// Assert
|
||||
expect(wrapper.emitted()["update:modelValue"][0]).toEqual([{answer: "Windshield"}]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("buttonQuestion.vue", () => {
|
||||
it("Should trigger event modelValue change with one string value on select if checked is true and only one option is selected", async () => {
|
||||
// Act
|
||||
const wrapper = shallowMount(buttonQuestion);
|
||||
await wrapper.setData({
|
||||
chosenAnswer: "Windshield"
|
||||
});
|
||||
wrapper.vm.isItemChecked(true);
|
||||
// Assert
|
||||
expect(wrapper.emitted()["update:modelValue"][0]).toEqual(["Windshield"]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("buttonQuestion.vue", () => {
|
||||
it("Should trigger event modelValue change with an array of string values on select if checked is true and multiple optiopns are chosen", async () => {
|
||||
// Act
|
||||
const wrapper = shallowMount(buttonQuestion);
|
||||
await wrapper.setData({
|
||||
modelValueAnswers: ["Windshield", "BackDoor"]
|
||||
});
|
||||
wrapper.vm.isItemChecked(true);
|
||||
// Assert
|
||||
expect(typeof wrapper.emitted()["update:modelValue"][0]).toEqual('object');
|
||||
});
|
||||
});
|
||||
|
||||
describe("buttonQuestion.vue", () => {
|
||||
it("Should not trigger event modelValue change on select if checked is false", async () => {
|
||||
// Act
|
||||
const wrapper = shallowMount(buttonQuestion);
|
||||
wrapper.vm.isItemChecked(false);
|
||||
// Assert
|
||||
expect(wrapper.emitted()["update:modelValue"][0]).toEqual([undefined]);
|
||||
});
|
||||
});
|
||||
|
|
@ -12,6 +12,7 @@
|
|||
<component :is="buttonType" v-for="answer in answers" :key="answer.Name ? answer.Name : answer"
|
||||
@mouseup="chooseAnswer(answer.Name ? answer.Name : answer)"
|
||||
@keyup.space="chooseAnswer(answer.Name ? answer.Name : answer)"
|
||||
@isChecked="isItemChecked"
|
||||
:buttonID="answer.Name ? answer.Name : answer"
|
||||
:value="answer.Name ? answer.Name : answer"
|
||||
:buttonLabel="answer.Text ? answer.Text : answer"
|
||||
|
|
@ -74,7 +75,7 @@ export default {
|
|||
isRequired: Boolean,
|
||||
isOverflowScrollable: Boolean,
|
||||
isWide: Boolean,
|
||||
modelValue: Array,
|
||||
modelValue: [Array, String],
|
||||
},
|
||||
computed: {
|
||||
getFieldSetClasses(){
|
||||
|
|
@ -94,18 +95,42 @@ export default {
|
|||
break;
|
||||
}
|
||||
return classes;
|
||||
}
|
||||
},
|
||||
},
|
||||
data(){
|
||||
return {
|
||||
modelValueAnswers: []
|
||||
modelValueAnswers: [],
|
||||
chosenAnswer: String
|
||||
}
|
||||
},
|
||||
created(){
|
||||
if(Array.isArray(this.answers) && this.answers.length === 1) {
|
||||
const onlyAnswer = typeof(this.answers[0]) === 'object' ? this.answers[0].Name : this.answers[0];
|
||||
this.$emit("update:modelValue", onlyAnswer);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
chooseAnswer(answer) {
|
||||
this.modelValueAnswers.includes(answer) ? this.modelValueAnswers.pop(answer) : this.modelValueAnswers.push(answer);
|
||||
this.$emit("update:modelValue", this.modelValueAnswers);
|
||||
}
|
||||
this.chosenAnswer = answer;
|
||||
},
|
||||
isItemChecked(val) {
|
||||
// Add or remove item to array of data to emit
|
||||
val ? this.modelValueAnswers.push(this.chosenAnswer) : this.modelValueAnswers.splice(this.modelValueAnswers.indexOf(this.chosenAnswer), 1);
|
||||
// Determine what data to emit
|
||||
let dataToEmit;
|
||||
switch(this.modelValueAnswers.length){
|
||||
case 0:
|
||||
dataToEmit = undefined
|
||||
break;
|
||||
case 1:
|
||||
dataToEmit = this.chosenAnswer
|
||||
break;
|
||||
default:
|
||||
dataToEmit = this.modelValueAnswers
|
||||
break;
|
||||
}
|
||||
this.$emit("update:modelValue", dataToEmit);
|
||||
},
|
||||
},
|
||||
components: {
|
||||
listButton,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,76 @@
|
|||
import { shallowMount } from "@vue/test-utils";
|
||||
import replaceOptionsQuestion from "@/layouts/vehicle-damage/replace-options-question/replace-options-question";
|
||||
import { getMountOptions } from "@/helpers/unit-test-helper.js";
|
||||
import store from "@/store";
|
||||
jest.mock("@/store", () => { return {}; }, {virtual: true});
|
||||
|
||||
describe("replace-options-question.vue", () => {
|
||||
test("Selected damage option is emitted upon selection.", async () => {
|
||||
|
||||
//Arrange
|
||||
const { wrapper } = setupMocks({ modelValueProp: ["Windshield"] });
|
||||
const damageToSelect = ["Backseat"];
|
||||
|
||||
//Act
|
||||
wrapper.setValue({ modelValue: damageToSelect });
|
||||
await wrapper.vm.$nextTick();
|
||||
|
||||
//Assert
|
||||
expect(wrapper.emitted()["update:modelValue"][0]).toEqual([{modelValue: ["Backseat"]}]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("replace-options-question.vue", () => {
|
||||
test("Answers to display filtered by data from api.", async () => {
|
||||
|
||||
//Arrange
|
||||
const { wrapper, cmsContent, replaceOptions } = setupMocks({ dataFromStoreApi: ["Windshield", "FrontDoor"]});
|
||||
|
||||
//Act
|
||||
replaceOptionsQuestion.methods.initializeComponent.call(wrapper.vm, cmsContent, replaceOptions, "car-group");
|
||||
|
||||
//Assert
|
||||
expect(wrapper.vm.answersToDisplay).toStrictEqual([ { Name: 'car-Windshield' }, { Name: 'car-FrontDoor' } ])
|
||||
});
|
||||
});
|
||||
|
||||
function setupMocks({
|
||||
modelValueProp = ["Windshield"],
|
||||
isAvailale = true,
|
||||
isMultiSelect = false,
|
||||
filterByVehicleCategory = false,
|
||||
groupName = "damageQuestion",
|
||||
cmsQuestionText = "CMS text goes here",
|
||||
cmsAnswers = [{Name: "car-Windshield"}, {Name: "car-BackDoor"}, {Name: "car-FrontDoor"}],
|
||||
dataFromStoreApi = [],
|
||||
}) {
|
||||
|
||||
//Mock store
|
||||
store.dispatch = jest.fn(() => dataFromStoreApi);
|
||||
store.getters = { vehicle: {year: 2019, make: 'honda', model: 'civc', style: '2 Door', category: 'CAR'} };
|
||||
const mountOptions = getMountOptions({
|
||||
store: {
|
||||
dispatch: store.dispatch,
|
||||
getters: store.getters,
|
||||
},
|
||||
});
|
||||
|
||||
//Mock props
|
||||
mountOptions.propsData = {
|
||||
modelValue: modelValueProp,
|
||||
isAvailable: isAvailale,
|
||||
isMultiSelect: isMultiSelect,
|
||||
filterByVehicleCategory: filterByVehicleCategory
|
||||
};
|
||||
|
||||
const wrapper = shallowMount(replaceOptionsQuestion, mountOptions);
|
||||
|
||||
//Mock CMS content
|
||||
const cmsContent = {
|
||||
groupName: groupName,
|
||||
QuestionText: cmsQuestionText,
|
||||
Answers: cmsAnswers,
|
||||
};
|
||||
const replaceOptions = dataFromStoreApi;
|
||||
return { wrapper, cmsContent, replaceOptions };
|
||||
}
|
||||
|
|
@ -1,15 +1,17 @@
|
|||
<template>
|
||||
<div class="replace-options-question">
|
||||
<buttonQuestion
|
||||
v-if="isAvailable && answersToDisplay.length > 1"
|
||||
:questionText="questionText"
|
||||
:isMultiSelect="isMultiSelect"
|
||||
:answers="answersToDisplay"
|
||||
:groupName="groupName"
|
||||
buttonType="listCard"
|
||||
v-model="modelValue"
|
||||
/>
|
||||
</div>
|
||||
<transition name="fade">
|
||||
<div class="replace-options-question">
|
||||
<buttonQuestion
|
||||
v-if="isAvailable && answersToDisplay.length > 1"
|
||||
:questionText="questionText"
|
||||
:isMultiSelect="isMultiSelect"
|
||||
:answers="answersToDisplay"
|
||||
:groupName="groupName"
|
||||
buttonType="listCard"
|
||||
v-model="modelValue"
|
||||
/>
|
||||
</div>
|
||||
</transition>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
|
@ -49,7 +51,7 @@ export default ({
|
|||
return this.filterByVehicleCategory ? name[0].toUpperCase() === store.getters.vehicle.category : name[0].toUpperCase() === store.getters.vehicle.category && this.replaceOptions.includes(name[1])
|
||||
})
|
||||
: [];
|
||||
}
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
modelValue(val) {
|
||||
|
|
@ -61,3 +63,15 @@ export default ({
|
|||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
transition: opacity 0.5s ease;
|
||||
}
|
||||
|
||||
.fade-enter-from,
|
||||
.fade-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ const navigationScenarios = {
|
|||
SELECTED_MODEL: "SELECTED_MODEL",
|
||||
SELECTED_MAKE: "SELECTED_MAKE",
|
||||
SELECTED_STYLE: "SELECTED_STYLE",
|
||||
VEHICLE_DAMAGE: "VEHICLE_DAMAGE",
|
||||
CLICKED_BACK: "CLICKED_BACK",
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<div class="list-group list-button-horizontal d-flex flex-column w-100 mb-2" @mouseup="handleClick(value)" @keyup.space="handleClick(value)">
|
||||
<input :type="isMultiSelect ? 'checkbox' : 'radio'" :id="buttonID" :name="groupName" :value="buttonID" :aria-required="isRequired" :data-focus-target="groupName" />
|
||||
<input :type="isMultiSelect ? 'checkbox' : 'radio'" :id="buttonID" :name="groupName" :value="buttonID" :aria-required="isRequired" :data-focus-target="groupName" v-model="modelValue" />
|
||||
<label tabindex="-1" :for="buttonID" :aria-labelledby="buttonID" class="d-flex flex-column justify-content-center py-3 px-4">
|
||||
<span class="m-0" :class="textPosition">{{buttonLabel}}</span>
|
||||
<span v-if="buttonLabelSubCopy" class="m-0 small" :class="textPosition">{{buttonLabelSubCopy}}</span>
|
||||
|
|
@ -33,7 +33,8 @@ export default {
|
|||
value: { // Field initial value
|
||||
type: String,
|
||||
default: ""
|
||||
}
|
||||
},
|
||||
modelValue: false
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
|
@ -51,6 +52,11 @@ export default {
|
|||
this.handleChange(value);
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
modelValue(){
|
||||
this.$emit('isChecked', this.modelValue);
|
||||
}
|
||||
},
|
||||
components: {
|
||||
loader,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<div class="list-group list-button d-flex flex-column w-100 mb-2" @mouseup="handleClick(value)" @keyup.space="handleClick(value)">
|
||||
<input :type="isMultiSelect ? 'checkbox' : 'radio'" :id="buttonID" :name="groupName" :value="buttonID" :aria-required="isRequired" :data-focus-target="groupName">
|
||||
<input :type="isMultiSelect ? 'checkbox' : 'radio'" :id="buttonID" :name="groupName" :value="buttonID" :aria-required="isRequired" :data-focus-target="groupName" v-model="modelValue">
|
||||
<label tabindex="-1" :for="buttonID" :aria-labelledby="buttonID" class="d-flex flex-column justify-content-center py-3 px-4">
|
||||
<span class="m-0" :class="textPosition">{{ buttonLabel }}</span>
|
||||
<span v-if="buttonLabelSubCopy" class="m-0 small" :class="textPosition">{{buttonLabelSubCopy}}</span>
|
||||
|
|
@ -30,9 +30,10 @@ export default {
|
|||
loaderPosition: String,
|
||||
sizeInRem: [Number,String],
|
||||
value: { // Field initial value
|
||||
type: String,
|
||||
type: [String, Number],
|
||||
default: ""
|
||||
}
|
||||
},
|
||||
modelValue: false
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
|
@ -50,6 +51,11 @@ export default {
|
|||
this.handleChange(value);
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
modelValue(){
|
||||
this.$emit('isChecked', this.modelValue);
|
||||
}
|
||||
},
|
||||
components: {
|
||||
loader,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -126,4 +126,66 @@ describe("list-card.vue", () => {
|
|||
|
||||
});
|
||||
|
||||
it("Should return flex row classes if isWide is true", async () => {
|
||||
// Act
|
||||
const wrapper = shallowMount(listCard, {
|
||||
propsData: {
|
||||
isRadioHorizontal: true,
|
||||
buttonLabel: "Windshield",
|
||||
buttonID: "List Card Checkbox",
|
||||
groupID: "radio-demo-1",
|
||||
groupName: "radio 1",
|
||||
buttonImage: "windshield-damage.svg",
|
||||
isRequired: true,
|
||||
isWide: true,
|
||||
buttonLabelSubCopy: ""
|
||||
},
|
||||
});
|
||||
|
||||
// Assert
|
||||
const label = wrapper.find("label");
|
||||
expect(label.classes()).toEqual(["d-flex", "w-100", "align-items-center", "px-2", "h-100", "flex-row", "py-r", "ps-3", "pe-8"]);
|
||||
});
|
||||
|
||||
it("Should return flex row classes if isWide is true and checkboxTop if buttonLabelSubCopy is true", async () => {
|
||||
// Act
|
||||
const wrapper = shallowMount(listCard, {
|
||||
propsData: {
|
||||
isRadioHorizontal: true,
|
||||
buttonLabel: "Windshield",
|
||||
buttonID: "List Card Checkbox",
|
||||
groupID: "radio-demo-1",
|
||||
groupName: "radio 1",
|
||||
buttonImage: "windshield-damage.svg",
|
||||
isRequired: true,
|
||||
isWide: true,
|
||||
buttonLabelSubCopy: "Button Subcopy"
|
||||
},
|
||||
});
|
||||
|
||||
// Assert
|
||||
const label = wrapper.find("label");
|
||||
expect(label.classes()).toEqual(["d-flex", "w-100", "align-items-center", "px-2", "h-100", "flex-row", "py-r", "ps-3", "pe-8", "checkboxTop"]);
|
||||
});
|
||||
|
||||
it("Should return flex column classes if isWide is false", async () => {
|
||||
// Act
|
||||
const wrapper = shallowMount(listCard, {
|
||||
propsData: {
|
||||
isRadioHorizontal: true,
|
||||
buttonLabel: "Windshield",
|
||||
buttonID: "List Card Checkbox",
|
||||
groupID: "radio-demo-1",
|
||||
groupName: "radio 1",
|
||||
buttonImage: "windshield-damage.svg",
|
||||
isRequired: true,
|
||||
isWide: false,
|
||||
},
|
||||
});
|
||||
|
||||
// Assert
|
||||
const label = wrapper.find("label");
|
||||
expect(label.classes()).toEqual(["d-flex", "w-100", "align-items-center", "px-2", "h-100", "flex-column", "pt-4", "pb-2"]);
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<!-- Heavily documented below -->
|
||||
<div :class="'col' + colLength">
|
||||
<div class="list-card w-100 rounded-3 d-flex align-items-center h-100" :class="isWide ? 'horizontal' : ''" @mouseup="handleClick(value)" @keyup.space="handleClick(value)">
|
||||
<div class="list-card w-100 rounded-3 d-flex align-items-center h-100" :class="isWide ? 'horizontal' : ''" @mouseup="handleChange(value)" @keyup.space="handleChange(value)">
|
||||
<input :type="isMultiSelect ? 'checkbox' : 'radio'" :id="buttonID" :name="groupName" :value="buttonID" :aria-required="isRequired" :data-focus-target="groupName" v-model="modelValue" />
|
||||
<label :for="buttonID" class="d-flex w-100 align-items-center px-2 h-100" :class="getLabelClasses" tabindex="-1">
|
||||
<img :id="buttonImageId" :class="!isWide ? 'order-1' : 'ms-auto order-3'" :src="buttonImage" :alt="altText" />
|
||||
|
|
@ -40,7 +40,7 @@ export default {
|
|||
default: ""
|
||||
},
|
||||
colLength: String,
|
||||
modelValue: String
|
||||
modelValue: false
|
||||
},
|
||||
computed: {
|
||||
getLabelClasses(){
|
||||
|
|
@ -55,10 +55,9 @@ export default {
|
|||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleClick(value){
|
||||
this.handleChange(value);
|
||||
this.$emit("update:modelValue", value);
|
||||
watch: {
|
||||
modelValue(){
|
||||
this.$emit('isChecked', this.modelValue);
|
||||
}
|
||||
},
|
||||
setup(props) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue