Merge remote-tracking branch 'origin/feature/CSR-762' into feature/CSR-731

This commit is contained in:
Scott Kiener 2022-10-24 11:48:10 -04:00
commit a4d379d2f7
14 changed files with 2126 additions and 1054 deletions

View file

@ -1,4 +1,5 @@
{ {
"tabWidth": 4, "tabWidth": 4,
"bracketSameLine": true "bracketSameLine": true,
"printWidth": 100
} }

View file

@ -28,7 +28,7 @@ module.exports = {
testMatch: ["**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)"], testMatch: ["**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)"],
coverageThreshold: { coverageThreshold: {
global: { global: {
statements: 80, statements: 85,
// Got the go ahead from Mark to temporarily lower this. Taking out initialize component made the year,make,model and style coverage drop a bit. Once unit tests for license plate lookup, vin lookup and address lookup are in the coverage should go back up to 90 // Got the go ahead from Mark to temporarily lower this. Taking out initialize component made the year,make,model and style coverage drop a bit. Once unit tests for license plate lookup, vin lookup and address lookup are in the coverage should go back up to 90
}, },
}, },

View file

@ -4,7 +4,7 @@
:for="buttonId" :for="buttonId"
@focusin="handleFocus" @focusin="handleFocus"
@focusout="handleBlur" @focusout="handleBlur"
@mousedown.left="handleEventAction('click', $event)"> @mousedown.left="handleEventAction(eventTypes.CLICK, $event)">
<input <input
:type="inputType" :type="inputType"
:id="buttonId" :id="buttonId"
@ -14,9 +14,9 @@
:aria-required="isRequired" :aria-required="isRequired"
:value="value" :value="value"
:checked="isChecked" :checked="isChecked"
@keypress.space="handleEventAction('space', $event)" @keypress.space="handleEventAction(eventTypes.SPACE, $event)"
@keypress.enter="handleEventAction('enter', $event)" @keypress.enter="handleEventAction(eventTypes.ENTER, $event)"
@change="handleEventAction('change', $event)" /> @change="handleEventAction(eventTypes.CHANGE, $event)" />
<slot></slot> <slot></slot>
</label> </label>
@ -48,10 +48,6 @@ export default {
}, },
methods: { methods: {
handleEventAction(eventType, e) { handleEventAction(eventType, e) {
// console.log({
// eventType,
// e
// })
if (this.isMultiSelect) { if (this.isMultiSelect) {
switch (eventType) { switch (eventType) {
case this.eventTypes.ENTER: case this.eventTypes.ENTER:
@ -93,7 +89,7 @@ export default {
} }
this.valueToEmit = newValue; this.valueToEmit = newValue;
} else { } else if (!this.isMultiSelect) {
this.valueToEmit = this.value; this.valueToEmit = this.value;
} }
@ -115,9 +111,10 @@ export default {
}); });
}, },
handlePushClickEventToGACheck(source) { handlePushClickEventToGACheck(source) {
// if from a click or click-like event
if (source === this.eventTypes.CLICK) { if (source === this.eventTypes.CLICK) {
this.pushClickEventToGA(); this.pushClickEventToGA();
} else { } else { // if from tabbing around
if ( if (
this.valueToEmit !== null && this.valueToEmit !== null &&
!this.isValueSelectedOnClick && !this.isValueSelectedOnClick &&
@ -129,8 +126,6 @@ export default {
} }
}, },
pushClickEventToGA(value) { pushClickEventToGA(value) {
console.log("PUSHHH")
console.log(this.$route)
this.pushEventToGA( this.pushEventToGA(
this.$route.query[queryStrings.FMG_PAGE], this.$route.query[queryStrings.FMG_PAGE],
this.GaActions.CLICKED, this.GaActions.CLICKED,
@ -139,7 +134,7 @@ export default {
this.valueToLogType this.valueToLogType
); );
this.setLastValuePushedToGa(this.value); this.setLastValuePushedToGa(value ?? this.value);
}, },
}, },
computed: { computed: {

View file

@ -3,171 +3,172 @@ import buttonQuestion from "@/common-components/button-question/button-question"
import { getMountOptions } from "@/helpers/unit-test-helper.js"; import { getMountOptions } from "@/helpers/unit-test-helper.js";
jest.mock( jest.mock(
"@/store", "@/store",
() => { () => {
return {}; return {};
}, },
{ virtual: true } { virtual: true }
); );
describe("buttonQuestion.vue", () => { describe("buttonQuestion.vue", () => {
it("Should show overflow classes on fieldset if isOverflowScrollable is true", () => { it("Should show overflow classes on fieldset if isOverflowScrollable is true", () => {
// Act // Act
const wrapper = shallowMount(buttonQuestion, { const wrapper = shallowMount(buttonQuestion, {
propsData: { propsData: {
isOverflowScrollable: true, isOverflowScrollable: true,
groupName: "group-name", groupName: "group-name",
}, },
}); });
// Assert // Assert
const fieldSet = wrapper.find("fieldset"); const fieldSet = wrapper.find("fieldset");
expect(fieldSet.classes()).toContain("overflow-scroll"); expect(fieldSet.classes()).toContain("overflow-scroll");
}); });
}); });
describe("buttonQuestion.vue", () => { describe("buttonQuestion.vue", () => {
it("Fieldset classes should contain row if button type is listCard", () => { it("Fieldset classes should contain row if button type is listCard", () => {
// Act // Act
const wrapper = shallowMount(buttonQuestion, { const wrapper = shallowMount(buttonQuestion, {
propsData: { propsData: {
buttonType: "listCard", buttonType: "listCard",
groupName: "group-name", groupName: "group-name",
}, },
});
// Assert
const Div = wrapper.find("fieldset div");
expect(Div.classes()).toContain("row");
}); });
// Assert
const Div = wrapper.find("fieldset div");
expect(Div.classes()).toContain("row");
});
}); });
describe("buttonQuestion.vue", () => { describe("buttonQuestion.vue", () => {
it("Fieldset classes should contain d-flex if button type is listButtonHorizontal", () => { it("Fieldset classes should contain d-flex if button type is listButtonHorizontal", () => {
// Act // Act
const wrapper = shallowMount(buttonQuestion, { const wrapper = shallowMount(buttonQuestion, {
propsData: { propsData: {
buttonType: "listButtonHorizontal", buttonType: "listButtonHorizontal",
groupName: "group-name", groupName: "group-name",
}, },
});
// Assert
const Div = wrapper.find("fieldset div");
expect(Div.classes()).toContain("d-flex");
}); });
// Assert
const Div = wrapper.find("fieldset div");
expect(Div.classes()).toContain("d-flex");
});
}); });
describe("buttonQuestion.vue", () => { describe("buttonQuestion.vue", () => {
it("Fieldset classes should contain ui-radio if button type is radio", () => { it("Fieldset classes should contain ui-radio if button type is radio", () => {
// Act // Act
const wrapper = shallowMount(buttonQuestion, { const wrapper = shallowMount(buttonQuestion, {
propsData: { propsData: {
buttonType: "radio", buttonType: "radio",
groupName: "group-name", groupName: "group-name",
}, },
});
// Assert
const Div = wrapper.find("fieldset div");
expect(Div.classes()).toContain("ui-radio");
}); });
// Assert
const Div = wrapper.find("fieldset div");
expect(Div.classes()).toContain("ui-radio");
});
}); });
// testing a computed property // testing a computed property
describe("buttonQuestion.vue", () => { describe("buttonQuestion.vue", () => {
it("getColLength should return '12' if prop isWide is set to true", () => { it("getColLength should return '12' if prop isWide is set to true", () => {
// Act // Act
const localThis = { isWide: true }; const localThis = { isWide: true };
expect(buttonQuestion.computed.getColLength.call(localThis)).toBe("12"); expect(buttonQuestion.computed.getColLength.call(localThis)).toBe("12");
});
});
describe("buttonQuestion.vue", () => {
it("getColLength should return '' if prop isWide is set to false", () => {
// Act
const localThis = {
isWide: false,
answers: ["a", "b"],
groupName: "group-name",
};
expect(buttonQuestion.computed.getColLength.call(localThis)).toBe("");
});
});
describe("buttonQuestion.vue", () => {
it("Should return answer.Text if prop useTextForValue is true", async () => {
// Act
const localThis = { useTextForValue: true };
const answer = { Name: "testName", Text: "testText" };
// Assert
expect(buttonQuestion.methods.getValue.call(localThis, answer)).toBe(
"testText"
);
});
});
describe("buttonQuestion.vue", () => {
it("Should return answer.Name if prop useTextForValue is false and there's not buttonLabel and answer.Name exists", async () => {
// Act
const localThis = { useTextForValue: false };
const answer = { Name: "testName", Text: "testText" };
// Assert
expect(buttonQuestion.methods.getValue.call(localThis, answer)).toBe(
"testName"
);
});
});
// TODO KO
describe("buttonQuestion.vue", () => {
describe.skip("handleAnswerChange", () => {
test("is radio => should emit captured value", async () => {
// Act
const wrapper = shallowMount(
buttonQuestion,
setupMocks({ propsData: { groupName: "group-name" } })
);
await wrapper.setProps({
answers: ["2022", "2021", "2020"],
isMultiSelect: false,
modelValue: "",
});
const val = "2021";
wrapper.vm.handleAnswerChange(val);
// Assert
expect(wrapper.emitted()["update:modelValue"][0]).toEqual(["2021"]);
}); });
});
test("is checkbox => should emit captured value", async () => { describe("buttonQuestion.vue", () => {
const wrapper = shallowMount( it("getColLength should return '' if prop isWide is set to false", () => {
buttonQuestion, // Act
setupMocks({ propsData: { groupName: "group-name" } }) const localThis = {
); isWide: false,
await wrapper.setProps({ answers: ["a", "b"],
answers: ["2022", "2021", "2020"], groupName: "group-name",
isMultiSelect: false, };
modelValue: "",
});
const val = ["2022", "2021", , "2019", "2020"];
wrapper.vm.handleAnswerChange(val);
// Assert expect(buttonQuestion.computed.getColLength.call(localThis)).toBe("");
expect(wrapper.emitted()["update:modelValue"][0]).toEqual([ });
["2022", "2021", , "2019", "2020"], });
]);
describe("buttonQuestion.vue", () => {
it("Should return answer.Text if prop useTextForValue is true", async () => {
// Act
const localThis = { useTextForValue: true };
const answer = { Name: "testName", Text: "testText" };
// Assert
expect(buttonQuestion.methods.getValue.call(localThis, answer)).toBe("testText");
});
});
describe("buttonQuestion.vue", () => {
it("Should return answer.Name if prop useTextForValue is false and there's not buttonLabel and answer.Name exists", async () => {
// Act
const localThis = { useTextForValue: false };
const answer = { Name: "testName", Text: "testText" };
// Assert
expect(buttonQuestion.methods.getValue.call(localThis, answer)).toBe("testName");
});
});
describe("buttonQuestion.vue", () => {
describe("selectedValues", () => {
test("is radio => should emit captured value", async () => {
// Arrange
const wrapper = shallowMount(
buttonQuestion,
setupMocks({ propsData: { groupName: "group-name" } })
);
await wrapper.setProps({
answers: ["2022", "2021", "2020"],
isMultiSelect: false,
modelValue: "",
});
// Act
wrapper.vm.selectedValues = "2021";
// Assert
expect(wrapper.emitted()["update:modelValue"][0][0]).toEqual("2021");
});
test("is checkbox => should emit captured value", async () => {
const wrapper = shallowMount(
buttonQuestion,
setupMocks({ propsData: { groupName: "group-name" } })
);
await wrapper.setProps({
answers: ["2022", "2021", "2020"],
isMultiSelect: false,
modelValue: "",
});
// Act
wrapper.vm.selectedValues = ["2022", "2021", "2020", "2019", "2020"];
// Assert
expect(wrapper.emitted()["update:modelValue"][0][0]).toEqual([
"2022",
"2021",
"2020",
"2019",
"2020",
]);
});
}); });
});
}); });
function setupMocks(mountOptionsMockData = {}) { function setupMocks(mountOptionsMockData = {}) {
const defaultMountOptions = { route: { query: { fmgPage: "page-name" } } }; const defaultMountOptions = { route: { query: { fmgPage: "page-name" } } };
const baseMountOptions = getMountOptions( const baseMountOptions = getMountOptions(
Object.assign(defaultMountOptions, mountOptionsMockData) Object.assign(defaultMountOptions, mountOptionsMockData)
); );
const allMountOptions = Object.assign(defaultMountOptions, baseMountOptions); const allMountOptions = Object.assign(defaultMountOptions, baseMountOptions);
return allMountOptions; return allMountOptions;
} }

View file

@ -1,14 +1,13 @@
/** /**
* Helper for GA click event. When the user mouse clicks on a `base-input-button`, we * Helper for GA click event. When the user mouse clicks on a `base-input-button`, we
* push the click event. When the user tabs through a list of radio buttons via a * push the click event. When the user tabs through a list of radio buttons via a
* keyboard, we only want to push the GA click event iff the select was deliberate * keyboard, we only want to push the GA click event if the selection was deliberate
* (space/enter key) or if there is a selection and the user tabs off of the radio group. * (space/enter key) or if there is a selection and the user tabs off of the radio group.
*/ */
let lastFocusedInputGroupName = ""; let lastFocusedInputGroupName = "";
let onButtonQuestionLostFocusCallback = null; let onButtonQuestionLostFocusCallback = null;
// TODO KO add tests
const handleAnyComponentFocus = (e) => { const handleAnyComponentFocus = (e) => {
const targetType = e.target.type; const targetType = e.target.type;
if (targetType !== "radio" && targetType !== "checkbox") { if (targetType !== "radio" && targetType !== "checkbox") {

View file

@ -0,0 +1,251 @@
import {
handleAnyComponentFocus,
handleButtonComponentFocus,
handleInputComponentBlur,
} from "@/helpers/button-question-focus-helper";
describe("buttonQuestionFocusHelper", () => {
let onButtonQuestionLostFocusCallbackOne = jest.fn();
let onButtonQuestionLostFocusCallbackTwo = jest.fn();
let focusOnInputInGroupOne;
let blurFromInputInGroupOne;
let focusOnInputInGroupTwo;
let blurFromInputInGroupTwo;
let focusOnNonRadioCheckboxElement;
beforeEach(() => {
onButtonQuestionLostFocusCallbackOne = jest.fn();
onButtonQuestionLostFocusCallbackTwo = jest.fn();
// Sanity check
expect(onButtonQuestionLostFocusCallbackOne).not.toHaveBeenCalled();
expect(onButtonQuestionLostFocusCallbackTwo).not.toHaveBeenCalled();
focusOnInputInGroupOne = () => {
handleButtonComponentFocus({
groupName: "group1",
});
};
blurFromInputInGroupOne = () => {
handleInputComponentBlur({
groupName: "group1",
onButtonQuestionLostFocusCallback: onButtonQuestionLostFocusCallbackOne,
});
};
focusOnInputInGroupTwo = () => {
handleButtonComponentFocus({
groupName: "group2",
});
};
blurFromInputInGroupTwo = () => {
handleInputComponentBlur({
groupName: "group2",
onButtonQuestionLostFocusCallback: onButtonQuestionLostFocusCallbackTwo,
});
};
focusOnNonRadioCheckboxElement = () => {
handleAnyComponentFocus({
target: {
type: "nonRadioCheckbox",
},
});
};
});
test("focus on input => no callbacks were called", () => {
// focus on input in group 1
focusOnInputInGroupOne();
// Assert
expect(onButtonQuestionLostFocusCallbackOne).not.toHaveBeenCalled();
expect(onButtonQuestionLostFocusCallbackTwo).not.toHaveBeenCalled();
});
test("focus on input, then focus on input in same group => no callbacks are called", () => {
// focus on input in group 1
focusOnInputInGroupOne();
// Assert
expect(onButtonQuestionLostFocusCallbackOne).not.toHaveBeenCalled();
expect(onButtonQuestionLostFocusCallbackTwo).not.toHaveBeenCalled();
// focus on input in group 1
blurFromInputInGroupOne();
focusOnInputInGroupOne();
// Assert
expect(onButtonQuestionLostFocusCallbackOne).not.toHaveBeenCalled();
expect(onButtonQuestionLostFocusCallbackTwo).not.toHaveBeenCalled();
});
test("focus on non-radio/checkbox, focus on input => no callbacks are called", () => {
// focus on non-radio/checkbox
focusOnNonRadioCheckboxElement();
// Assert
expect(onButtonQuestionLostFocusCallbackOne).not.toHaveBeenCalled();
expect(onButtonQuestionLostFocusCallbackTwo).not.toHaveBeenCalled();
// focus on input
// focus on input in group 1
focusOnInputInGroupOne();
// Assert
expect(onButtonQuestionLostFocusCallbackOne).not.toHaveBeenCalled();
expect(onButtonQuestionLostFocusCallbackTwo).not.toHaveBeenCalled();
});
test("focus on input in group 1, then focus on input in different group => callback for group 1 is called", () => {
// focus on input in group 1
focusOnInputInGroupOne();
// Assert
expect(onButtonQuestionLostFocusCallbackOne).not.toHaveBeenCalled();
expect(onButtonQuestionLostFocusCallbackTwo).not.toHaveBeenCalled();
// focus on input in different group
blurFromInputInGroupOne();
focusOnInputInGroupTwo();
// Assert
expect(onButtonQuestionLostFocusCallbackOne).toHaveBeenCalledTimes(1);
expect(onButtonQuestionLostFocusCallbackTwo).not.toHaveBeenCalled();
});
test("focus on input in group 1, focus on input in same group, then focus on input in different group => callback for group 1 is called", () => {
// focus on input in group 1
focusOnInputInGroupOne();
// Assert
expect(onButtonQuestionLostFocusCallbackOne).not.toHaveBeenCalled();
expect(onButtonQuestionLostFocusCallbackTwo).not.toHaveBeenCalled();
// focus on input in same group
blurFromInputInGroupOne();
focusOnInputInGroupOne();
// Assert
expect(onButtonQuestionLostFocusCallbackOne).not.toHaveBeenCalled();
expect(onButtonQuestionLostFocusCallbackTwo).not.toHaveBeenCalled();
// focus on input in different group
blurFromInputInGroupOne();
focusOnInputInGroupTwo();
// Assert
expect(onButtonQuestionLostFocusCallbackOne).toHaveBeenCalledTimes(1);
expect(onButtonQuestionLostFocusCallbackTwo).not.toHaveBeenCalled();
});
test("focus on input in group 1, focus on non-radio/checkbox element => callback from group 1 is called", () => {
// focus on input in group 1
focusOnInputInGroupOne();
// Assert
expect(onButtonQuestionLostFocusCallbackOne).not.toHaveBeenCalled();
expect(onButtonQuestionLostFocusCallbackTwo).not.toHaveBeenCalled();
// focus on input in group 2
blurFromInputInGroupOne();
focusOnNonRadioCheckboxElement();
// Assert
expect(onButtonQuestionLostFocusCallbackOne).toHaveBeenCalledTimes(1);
expect(onButtonQuestionLostFocusCallbackTwo).not.toHaveBeenCalled();
});
test("focus on input in group 1, focus on input in group 2, focus on non-radio/checkbox element => both callbacks are called", () => {
// focus on input in group 1
focusOnInputInGroupOne();
// Assert
expect(onButtonQuestionLostFocusCallbackOne).not.toHaveBeenCalled();
expect(onButtonQuestionLostFocusCallbackTwo).not.toHaveBeenCalled();
// focus on input in group 2
blurFromInputInGroupOne();
focusOnInputInGroupTwo();
// Assert
expect(onButtonQuestionLostFocusCallbackOne).toHaveBeenCalledTimes(1);
expect(onButtonQuestionLostFocusCallbackTwo).toHaveBeenCalledTimes(0);
// focus on non-radio/checkbox
blurFromInputInGroupTwo();
focusOnNonRadioCheckboxElement();
// Assert
expect(onButtonQuestionLostFocusCallbackOne).toHaveBeenCalledTimes(1);
expect(onButtonQuestionLostFocusCallbackTwo).toHaveBeenCalledTimes(1);
});
test("focus on input in group 1, focus on input in group 2, focus on input in group 1 => both callbacks are called", () => {
// focus on input in group 1
focusOnInputInGroupOne();
// Assert
expect(onButtonQuestionLostFocusCallbackOne).not.toHaveBeenCalled();
expect(onButtonQuestionLostFocusCallbackTwo).not.toHaveBeenCalled();
// focus on input in group 2
blurFromInputInGroupOne();
focusOnInputInGroupTwo();
// Assert
expect(onButtonQuestionLostFocusCallbackOne).toHaveBeenCalledTimes(1);
expect(onButtonQuestionLostFocusCallbackTwo).toHaveBeenCalledTimes(0);
// focus on input in group 1
blurFromInputInGroupTwo();
focusOnInputInGroupOne();
// Assert
expect(onButtonQuestionLostFocusCallbackOne).toHaveBeenCalledTimes(1);
expect(onButtonQuestionLostFocusCallbackTwo).toHaveBeenCalledTimes(1);
});
test("go back and forth a lot => correct callbacks are called at the right time", () => {
// Arrange/Act
// focus on input in group 1
focusOnInputInGroupOne();
// Assert
expect(onButtonQuestionLostFocusCallbackOne).not.toHaveBeenCalled();
expect(onButtonQuestionLostFocusCallbackTwo).not.toHaveBeenCalled();
// focus on input in group 2
blurFromInputInGroupOne();
focusOnInputInGroupTwo();
// Assert
expect(onButtonQuestionLostFocusCallbackOne).toHaveBeenCalledTimes(1);
expect(onButtonQuestionLostFocusCallbackTwo).not.toHaveBeenCalled();
// focus on input in group 1
blurFromInputInGroupTwo();
focusOnInputInGroupOne();
// Assert
expect(onButtonQuestionLostFocusCallbackOne).toHaveBeenCalledTimes(1);
expect(onButtonQuestionLostFocusCallbackTwo).toHaveBeenCalledTimes(1);
// focus on non-radio/checkbox element
blurFromInputInGroupOne();
focusOnNonRadioCheckboxElement();
// Assert
expect(onButtonQuestionLostFocusCallbackOne).toHaveBeenCalledTimes(2);
expect(onButtonQuestionLostFocusCallbackTwo).toHaveBeenCalledTimes(1);
// focus on input in group 1
focusOnInputInGroupOne();
expect(onButtonQuestionLostFocusCallbackOne).toHaveBeenCalledTimes(2);
expect(onButtonQuestionLostFocusCallbackTwo).toHaveBeenCalledTimes(1);
});
});

View file

@ -22,6 +22,14 @@ describe("windshield-chip-count-question.vue", () => {
//Assert //Assert
expect(wrapper.emitted()["update:modelValue"][0]).toEqual([2]); expect(wrapper.emitted()["update:modelValue"][0]).toEqual([2]);
}); });
test("selectedValue matches modelValue", () => {
// Arrange/Act
const { wrapper } = setupMocks({ modelValueProp: 2 });
// Assert
expect(wrapper.vm.selectedValue).toBe(2);
});
}); });
function setupMocks({ function setupMocks({

View file

@ -5,150 +5,224 @@ import { settleAllPromises } from "@/helpers/layout-helper.js";
import { nextTick } from "vue"; import { nextTick } from "vue";
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper"; import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
import baseMixin from "@/mixins/base-mixin.js"; import baseMixin from "@/mixins/base-mixin.js";
import store from "@/store";
// Components // Components
import vehicleMake from "@/layouts/vehicle-make/vehicle-make.vue"; import vehicleMake from "@/layouts/vehicle-make/vehicle-make.vue";
import makeQuestion from "@/layouts/vehicle-make/make-question/make-question"; import makeQuestion from "@/layouts/vehicle-make/make-question/make-question";
jest.mock("@/store", () => ({ jest.mock("@/store", () => ({
commit: jest.fn(), commit: jest.fn(),
dispatch: jest.fn(), dispatch: jest.fn(),
getters: { // getters: jest.fn().mockImplementation(() => ({
vehicle: { // vehicle: {
year: 2019, // year: 2019,
}, // },
}, // })),
})); }));
// Mock fetchCmsContentForPage // Mock fetchCmsContentForPage
jest.mock("@/helpers/cms-content-helper", () => ({ jest.mock("@/helpers/cms-content-helper", () => ({
fetchCmsContentForPage: jest.fn(), fetchCmsContentForPage: jest.fn(),
})); }));
// Mock our module for promises. // Mock our module for promises.
jest.mock("@/helpers/layout-helper.js", () => ({ jest.mock("@/helpers/layout-helper.js", () => ({
settleAllPromises: jest.fn(), settleAllPromises: jest.fn(),
})); }));
describe("vehicle-make.vue", () => { describe("vehicle-make.vue", () => {
test("Make question component is initized with api data", async (done) => { test("Make question component is initized with api data", async (done) => {
//Arrange //Arrange
const makeQuestionInitialData = ["honda", "ford", "dodge"]; const makeQuestionInitialData = ["honda", "ford", "dodge"];
const { wrapper, apiPromise } = setupMocks({ const { wrapper, apiPromise } = setupMocks({
makeQuestionInitialData: makeQuestionInitialData, makeQuestionInitialData: makeQuestionInitialData,
}); });
//Act //Act
vehicleMake.beforeRouteEnter.call( vehicleMake.beforeRouteEnter.call(
wrapper.vm, wrapper.vm,
{ query: { fmgPage: "vehicle-make" } }, { query: { fmgPage: "vehicle-make" } },
undefined, undefined,
(c) => c(wrapper.vm) (c) => c(wrapper.vm)
); );
//Assert //Assert
apiPromise.finally(() => { apiPromise.finally(() => {
expect(makeQuestion.methods.initializeComponent).toHaveBeenCalledWith( expect(makeQuestion.methods.initializeComponent).toHaveBeenCalledWith(
makeQuestionInitialData makeQuestionInitialData
); );
done(); done();
});
}); });
});
}); });
describe("vehicle-make.vue", () => { describe("vehicle-make.vue", () => {
test("BackButtonAction triggers a router.navigateWithoutSaving change", async (done) => { test("BackButtonAction triggers a router.navigateWithoutSaving change", async (done) => {
//Arrange //Arrange
const { wrapper, apiPromise } = setupMocks({ const { wrapper, apiPromise } = setupMocks({
pageHeaderWidgetHeaderText: "Select a make to get started", pageHeaderWidgetHeaderText: "Select a make to get started",
mountOptionsMockData: { mountOptionsMockData: {
router: { router: {
navigate: jest.fn(), navigate: jest.fn(),
navigateWithoutSaving: jest.fn(), navigateWithoutSaving: jest.fn(),
}, },
}, },
}); });
//Act //Act
vehicleMake.beforeRouteEnter.call( vehicleMake.beforeRouteEnter.call(
wrapper.vm, wrapper.vm,
{ query: { fmgPage: "vehicle-make" } }, { query: { fmgPage: "vehicle-make" } },
undefined, undefined,
(c) => c(wrapper.vm) (c) => c(wrapper.vm)
); );
wrapper.vm.backButtonAction(); wrapper.vm.backButtonAction();
await nextTick(); await nextTick();
//Assert //Assert
apiPromise.finally(() => { apiPromise.finally(() => {
expect(wrapper.vm.$router.navigateWithoutSaving).toHaveBeenCalled(); expect(wrapper.vm.$router.navigateWithoutSaving).toHaveBeenCalled();
done(); done();
});
}); });
});
}); });
describe("vehicle-make.vue", () => { describe("vehicle-make.vue", () => {
test("Year set, arePagePrerequisitesValid should be true ", async () => { describe("arePagePrerequisitesValue", () => {
//Arrange test("Year set, arePagePrerequisitesValid should be true", async () => {
const { wrapper } = setupMocks({}); //Arrange
const { wrapper } = setupMocks({
vehicleData: {
year: 2019
}
});
//Act //Act
vehicleMake.beforeRouteEnter.call( vehicleMake.beforeRouteEnter.call(
wrapper.vm, wrapper.vm,
{ query: { fmgPage: "vehicle-make" } }, { query: { fmgPage: "vehicle-make" } },
undefined, undefined,
(c) => c(wrapper.vm) (c) => c(wrapper.vm)
); );
let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid(); let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid();
//Assert //Assert
expect(arePagePrerequisitesValid).toBe(true); expect(arePagePrerequisitesValid).toBe(true);
}); });
test("Year not set, arePagePrerequisitesValid should be false", async () => {
//Arrange
store.getters.vehicle.year = jest.fn().mockReturnValueOnce(undefined);
const { wrapper } = setupMocks({});
//Act
let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid();
//Assert
expect(arePagePrerequisitesValid).toBe(false);
});
});
test("selectedMake changes => save make in store", async () => {
//Arrange
const { wrapper } = setupMocks({
mountOptionsMockData: {
router: {
navigate: jest.fn(),
navigateWithSaving: jest.fn(),
},
}
});
// Act
await wrapper.setData({
selectedMake: "Make",
});
await wrapper.vm.$nextTick();
// Assert
expect(wrapper.vm.dispatchStoreAction).toHaveBeenCalledTimes(1);
expect(wrapper.vm.dispatchStoreAction).toHaveBeenCalledWith(
"saveVehicleMake",
"Make",
false
);
});
test("selectedMake changes => navigate with saving", async () => {
//Arrange
const { wrapper } = setupMocks({
mountOptionsMockData: {
router: {
navigate: jest.fn(),
navigateWithSaving: jest.fn(),
},
route: {
fmgPage: "test",
},
},
});
// Act
await wrapper.setData({
selectedMake: "Make",
});
// Assert
expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalledTimes(1);
expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalledWith(
"SELECTED_MAKE",
expect.anything()
);
});
}); });
function setupMocks({ function setupMocks({
vehicleMakeQuestionCmsContent = {}, vehicleMakeQuestionCmsContent = {},
makeQuestionInitialData = {}, makeQuestionInitialData = {},
pageHeaderWidgetHeaderText = {}, pageHeaderWidgetHeaderText = {},
mountOptionsMockData = {}, mountOptionsMockData = {},
vehicleData = {}
}) { }) {
//Mock api responses //Mock api responses
const apiResponses = { const apiResponses = {
cmsContent: { cmsContent: {
FunnelSubHeaderWidget: pageHeaderWidgetHeaderText, FunnelSubHeaderWidget: pageHeaderWidgetHeaderText,
VehicleMakeQuestion: vehicleMakeQuestionCmsContent, VehicleMakeQuestion: vehicleMakeQuestionCmsContent,
VehicleBannerWidget: { VehicleBannerWidget: {
GenericVehicleImage: GenericVehicleImage:
"https://digitalconsumercms-dev.safelite.com/images/default-source/default-album/blurred-image.jpg?sfvrsn=a6ce3034_3", "https://digitalconsumercms-dev.safelite.com/images/default-source/default-album/blurred-image.jpg?sfvrsn=a6ce3034_3",
}, },
FunnelHeaderWidget: { FunnelHeaderWidget: {
LogoImage: LogoImage:
"https://digitalconsumercms-dev.safelite.com/images/default-source/default-album/safelite-logo.svg?sfvrsn=45e7ed06_3", "https://digitalconsumercms-dev.safelite.com/images/default-source/default-album/safelite-logo.svg?sfvrsn=45e7ed06_3",
}, },
}, },
makeQuestionInitialData: makeQuestionInitialData, makeQuestionInitialData: makeQuestionInitialData,
}; };
const apiPromise = Promise.resolve(apiResponses); const apiPromise = Promise.resolve(apiResponses);
fetchCmsContentForPage.mockImplementation(() => Promise.resolve()); store.getters = {
settleAllPromises.mockImplementation(() => apiPromise); vehicle: vehicleData
}
//Mock make question methods fetchCmsContentForPage.mockImplementation(() => Promise.resolve());
makeQuestion.methods = { settleAllPromises.mockImplementation(() => apiPromise);
loadInitialData: jest.fn(),
initializeComponent: jest.fn(),
};
const mountOptions = getMountOptions(mountOptionsMockData); //Mock make question methods
const wrapper = shallowMount(vehicleMake, mountOptions); makeQuestion.methods = {
const makeQuestionWrapper = wrapper.findComponent({ name: "makeQuestion" }); loadInitialData: jest.fn(),
makeQuestionWrapper.vm.initializeComponent = initializeComponent: jest.fn(),
makeQuestion.methods.initializeComponent; };
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; wrapper.vm.setCmsContent = baseMixin.methods.setCmsContent;
return { wrapper, apiPromise }; return { wrapper, apiPromise };
} }

View file

@ -148,7 +148,7 @@ describe("vehicle-parts.vue", () => {
expect(arePagePrerequisitesValid).toBe(true); expect(arePagePrerequisitesValid).toBe(true);
}); });
test.only("Initial data, should populate this.selectedGlassParts", async () => { test("Initial data, should populate this.selectedGlassParts", async () => {
//Arrange //Arrange
store.getters.pageData.mockReturnValue(basePartResponse); store.getters.pageData.mockReturnValue(basePartResponse);

View file

@ -13,6 +13,7 @@ export default {
buttonAuxillaryCopy: String, buttonAuxillaryCopy: String,
buttonFooterCopy: String, buttonFooterCopy: String,
buttonImage: String, buttonImage: String,
buttonImageId: String,
altText: { altText: {
type: String, type: String,
default: "", default: "",

View file

@ -1,81 +1,317 @@
import { mount } from "@vue/test-utils";
import baseInputButton from "@/common-components/base-input-button/base-input-button";
import inputButtonWrapperMixin from "@/mixins/input-button-wrapper-mixin";
import listButtonHorizontal from "@/ux-components/list-button-horizontal/list-button-horizontal";
import listButton from "@/ux-components/list-button/list-button";
import listCard from "@/ux-components/list-card/list-card";
import radio from "@/ux-components/radio/radio";
describe("input-button-wrapper-mixin", () => { describe("input-button-wrapper-mixin", () => {
describe("mouse clicks", () => { describe("mouse clicks", () => {
describe("checkbox", () => { describe("checkbox", () => {
test.todo("clicking once checks the baseInputButton"); test("click on both => both are selected", async () => {
// Arrange
const { wrapper } = setupBaseInputButtonWrapper({
mockData: {
isMultiSelect: true,
},
});
test.todo("clicking twice unchecks the baseInputButton"); // Act
const buttonWrappers = wrapper.findAllComponents({
name: "baseInputButtonWrapper",
});
const inputButtonOne = buttonWrappers.at(0);
const inputButtonTwo = buttonWrappers.at(1);
expect(inputButtonOne.vm.isMultiSelect).toBe(true);
expect(inputButtonTwo.vm.isMultiSelect).toBe(true);
expect(wrapper.vm.value).toEqual([]);
test.todo( await inputButtonOne.find("input").trigger("click");
"is initially checked => checking unchecks the baseInputButton" await inputButtonTwo.find("input").trigger("click");
);
test.todo("clicked => correct event and value are emitted"); // Assert
expect(wrapper.vm.value).toEqual(["value1", "value2"]);
});
test("click input 1, 2, 1 => only input 2 selected", async () => {
// Arrange
const { wrapper } = setupBaseInputButtonWrapper({
mockData: {
isMultiSelect: true,
},
});
// Act
const buttonWrappers = wrapper.findAllComponents({
name: "baseInputButtonWrapper",
});
const inputButtonOne = buttonWrappers.at(0);
const inputButtonTwo = buttonWrappers.at(1);
expect(inputButtonOne.vm.isMultiSelect).toBe(true);
expect(inputButtonTwo.vm.isMultiSelect).toBe(true);
expect(wrapper.vm.value).toEqual([]);
await inputButtonOne.find("input").trigger("click");
await inputButtonTwo.find("input").trigger("click");
await inputButtonOne.find("input").trigger("click");
// Assert
expect(wrapper.vm.value).toEqual(["value2"]);
});
}); });
describe("radio", () => { describe("radio", () => {
test.todo("clicking once selects the baseInputButton"); test("click on both => last clicked is selected", async () => {
// Arrange
const { wrapper } = setupBaseInputButtonWrapper({
mockData: {
isMultiSelect: false,
},
});
test.todo("clicking twice keeps the baseInputButton selected"); // Act
const buttonWrappers = wrapper.findAllComponents({
name: "baseInputButtonWrapper",
});
const inputButtonOne = buttonWrappers.at(0);
const inputButtonTwo = buttonWrappers.at(1);
expect(inputButtonOne.vm.isMultiSelect).toBe(false);
expect(inputButtonTwo.vm.isMultiSelect).toBe(false);
expect(wrapper.vm.value).toEqual("");
test.todo( await inputButtonOne.find("input").trigger("click");
"is initially selected => click keeps the baseInputButton selected" await inputButtonTwo.find("input").trigger("click");
);
test.todo("clicked => correct event and value are emitted"); // Assert
expect(wrapper.vm.value).toEqual("value2");
});
test("click input 1, 2, 1 => input 1 is selected", async () => {
// Arrange
const { wrapper } = setupBaseInputButtonWrapper({
mockData: {
isMultiSelect: false,
},
});
// Act
const buttonWrappers = wrapper.findAllComponents({
name: "baseInputButtonWrapper",
});
const inputButtonOne = buttonWrappers.at(0);
const inputButtonTwo = buttonWrappers.at(1);
expect(inputButtonOne.vm.isMultiSelect).toBe(false);
expect(inputButtonTwo.vm.isMultiSelect).toBe(false);
expect(wrapper.vm.value).toEqual("");
await inputButtonOne.find("input").trigger("click");
await inputButtonTwo.find("input").trigger("click");
await inputButtonOne.find("input").trigger("click");
// Assert
expect(wrapper.vm.value).toEqual("value1");
});
}); });
}); });
describe("keyboard navigation and", () => { describe("initial values", () => {
describe("checkbox", () => { describe("checkbox", () => {
test.todo( const defaultCheckedCases = [
"focus on a checkbox => inputButtonClicked is not emitted" [["value2"], false, true],
); [["value1", "value2"], true, true],
[["value1"], true, false],
[[], false, false],
];
test.each(defaultCheckedCases)(
"initial value is %s => correct input buttons are selected",
async (modelValue, isInputButtonOneChecked, isInputButtonTwoChecked) => {
// Arrange
const { wrapper } = setupBaseInputButtonWrapper({
mockData: {
isMultiSelect: true,
initialValue: modelValue,
},
});
test.todo( // Act
"blur from a checkbox => inputButtonClicked is not emitted" const buttonWrappers = wrapper.findAllComponents({
); name: "baseInputButtonWrapper",
});
const inputs = wrapper.findAll("input");
const inputButtonOne = buttonWrappers.at(0);
const inputButtonTwo = buttonWrappers.at(1);
test.todo( // Assert
"focus and click space on a checkbox => inputButtonClicked is emitted with correct value" expect(inputButtonOne.vm.isMultiSelect).toBe(true);
); expect(inputButtonTwo.vm.isMultiSelect).toBe(true);
expect(inputs[0].element.checked).toBe(isInputButtonOneChecked);
test.todo( expect(inputs[1].element.checked).toBe(isInputButtonTwoChecked);
"focus and click space on a checkbox that is already checked => inputButtonClicked is emitted with correct value" expect(wrapper.vm.value).toEqual(modelValue);
); }
test.todo(
"focus and click enter on a checkbox => inputButtonClicked is emitted with correct value"
);
test.todo(
"focus and click enter on a checkbox that is already checked => inputButtonClicked is emitted with correct value"
); );
}); });
describe("radio", () => { describe("radio", () => {
test.todo( const defaultCheckedCases = [
"focus on a radio button => inputButtonClicked is not emitted" ["", false, false],
); ["value1", true, false],
["value2", false, true],
[[], false, false],
];
test.each(defaultCheckedCases)(
"initial value is %s => correct input buttons are selected",
async (modelValue, isInputButtonOneChecked, isInputButtonTwoChecked) => {
// Arrange
const { wrapper } = setupBaseInputButtonWrapper({
mockData: {
isMultiSelect: false,
initialValue: modelValue,
},
});
test.todo( // Act
"blur from a radio button => inputButtonClicked is not emitted" const buttonWrappers = wrapper.findAllComponents({
); name: "baseInputButtonWrapper",
});
const inputs = wrapper.findAll("input");
const inputButtonOne = buttonWrappers.at(0);
const inputButtonTwo = buttonWrappers.at(1);
test.todo( // Assert
"focus and click space on a radio button => inputButtonClicked is emitted with correct value" expect(inputButtonOne.vm.isMultiSelect).toBe(false);
expect(inputButtonTwo.vm.isMultiSelect).toBe(false);
expect(inputs[0].element.checked).toBe(isInputButtonOneChecked);
expect(inputs[1].element.checked).toBe(isInputButtonTwoChecked);
expect(wrapper.vm.value).toEqual(modelValue);
}
); );
});
});
test.todo( // shared checks between components that use input-button-wrapper-mixin
"focus and click space on a radio button that is already selected => inputButtonClicked is emitted with correct value" describe("shared checks", () => {
); const inputButtonComponents = [listButtonHorizontal, listButton, listCard, radio];
test.each(inputButtonComponents.map((x) => [x.name, x]))(
"%s - should return input type checkbox if isMultiSelect is true",
async (name, inputButtonComponent) => {
// Act
const { wrapper } = setupMocksForComponentsUsingInputButtonWrapperMixin({
component: inputButtonComponent,
mockData: {
propsData: {
isMultiSelect: true,
},
},
});
test.todo( // Assert
"focus and click enter on a radio button => inputButtonClicked is emitted with correct value" const input = wrapper.find("input");
); expect(input.attributes().type).toEqual("checkbox");
}
);
test.todo( test.each(inputButtonComponents.map((x) => [x.name, x]))(
"focus and click enter on a radio button that is already selected => inputButtonClicked is emitted with correct value" "%s - return input type radio if isMultiSelect is false or not specified",
async (name, inputButtonComponent) => {
// Act
const { wrapper } = setupMocksForComponentsUsingInputButtonWrapperMixin({
component: inputButtonComponent,
mockData: {
propsData: {
isMultiSelect: false,
},
},
});
// Assert
const input = wrapper.find("input");
expect(input.attributes().type).toEqual("radio");
}
);
const selectedValues = ["something", ["test"]];
inputButtonComponents.forEach((inputButtonComponent) => {
test.each(selectedValues)(
`${inputButtonComponent.name} with selectedValue %s - should emit button value on click`,
async (selectedValue) => {
// Act
const { wrapper } = setupMocksForComponentsUsingInputButtonWrapperMixin({
component: inputButtonComponent,
mockData: {
propsData: {
isRadioHorizontal: true,
buttonLabel: "Windshield",
value: "List Card Checkbox",
groupID: "radio-demo-1",
groupName: "radio 1",
buttonImage: "windshield-damage.svg",
isRequired: true,
isWide: false,
modelValue: ["List Card Checkbox"],
buttonID: "list-card-id",
},
},
});
// Act
wrapper.vm.selectedValue = selectedValue;
await wrapper.vm.$nextTick();
// Assert
expect(wrapper.emitted()["update:modelValue"][0][0]).toEqual(selectedValue);
}
); );
}); });
}); });
}); });
function setupMocksForComponentsUsingInputButtonWrapperMixin({ mockData, component }) {
const wrapper = mount(component, {
...mockData,
propsData: {
...mockData.propsData,
groupName: "my-group",
modelValue: mockData.propsData?.isMultiSelect ? ["5"] : "5",
value: "4",
},
mixins: [inputButtonWrapperMixin],
});
return { wrapper };
}
function setupBaseInputButtonWrapper({ mockData = {} }) {
baseInputButton.methods.pushClickEventToGA = jest.fn();
const baseInputButtonWrapper = {
name: "baseInputButtonWrapper",
components: { baseInputButton },
template: '<div><baseInputButton v-bind="$props" v-model="selectedValue" /></div>',
mixins: [inputButtonWrapperMixin],
};
let parentComponentTemplate = `<div>`;
parentComponentTemplate += `<baseInputButtonWrapper v-model="value" groupName="myGroupName" :isMultiSelect="${mockData.isMultiSelect}" value="value1" />`;
parentComponentTemplate += `<baseInputButtonWrapper v-model="value" groupName="myGroupName" :isMultiSelect="${mockData.isMultiSelect}" value="value2" />`;
parentComponentTemplate += `</div>`;
const wrapper = mount(
{
data() {
return {
value: mockData.initialValue ?? (mockData.isMultiSelect ? [] : ""),
$route: {
query: {
fmgPage: "myPage",
},
},
};
},
template: parentComponentTemplate,
components: { baseInputButtonWrapper },
},
{}
);
return { wrapper };
}

View file

@ -1,202 +1,139 @@
import { shallowMount, mount } from "@vue/test-utils"; import { mount } from "@vue/test-utils";
import listButtonHorizontal from "./list-button-horizontal"; import listButtonHorizontal from "./list-button-horizontal";
import { nextTick } from "vue";
import { GaActions } from "@/constants/analytics";
import inputButtonWrapperMixin from "@/mixins/input-button-wrapper-mixin"; import inputButtonWrapperMixin from "@/mixins/input-button-wrapper-mixin";
describe("list-button-horizontal.vue", () => { describe("list-button-horizontal.vue", () => {
// TODO KO Have this moved out to somewhere shared describe("styling/UI", () => {
describe("Shared baseInputButton checks", () => { it("Should return screen reader text", async () => {
it("Should return input type checkbox if isMultiSelect is true", async () => { // Act
// Act const { wrapper } = setupMocks({
const { wrapper } = setupMocks({ mockData: {
mockData: { propsData: {
propsData: { screenReaderOnlyText: "Screen Reader Only Text",
isMultiSelect: true, },
}, },
}, });
});
// Assert // Assert
const input = wrapper.find("input"); const paragraph = wrapper.find("span.sr-only");
expect(input.attributes().type).toEqual("checkbox");
expect(paragraph.text()).toEqual("Screen Reader Only Text");
});
it("Should return text alignment class", async () => {
// Act
const { wrapper } = setupMocks({
mockData: {
propsData: {
textPosition: "text-center",
},
},
});
// Assert
const paragraph = wrapper.find("span.m-0");
expect(paragraph.attributes("class")).toContain("text-center");
});
it("Should return aria-required state", async () => {
// Act
const { wrapper } = setupMocks({
mockData: {
propsData: {
isRequired: true,
},
},
});
// Assert
const input = wrapper.find("input");
expect(input.attributes()["aria-required"]).toEqual("true");
});
it("is cash or insurance button => has 'radio-fancy' class", () => {
// Arrange/Act
const { wrapper } = setupMocks({
mockData: {
propsData: {
isCashOrInsurance: true,
},
},
});
// Assert
const label = wrapper.find("label");
expect(label.classes()).toContain("radio-fancy");
});
test("has buttonLabel => displays buttonLabel", () => {
// Arrange/Act
const { wrapper } = setupMocks({
mockData: {
propsData: {
buttonLabel: "Surprise!",
},
},
});
// Assert
const content = wrapper.find(".list-button-horizontal-content");
expect(content.isVisible()).toBe(true);
expect(content.text()).toContain("Surprise!");
});
test("has buttonLabelSubCopy => displays buttonLabelSubCopy", () => {
// Arrange/Act
const { wrapper } = setupMocks({
mockData: {
propsData: {
buttonLabel: "Surprise!",
buttonLabelSubCopy: "Super duper surprise :)",
},
},
});
// Assert
const content = wrapper.find(".list-button-horizontal-content");
expect(content.isVisible()).toBe(true);
expect(content.text()).toContain("Super duper surprise :)");
});
test("has screenReaderOnlyText => displays screenReaderOnlyText", () => {
// Arrange/Act
const { wrapper } = setupMocks({
mockData: {
propsData: {
buttonLabel: "Surprise!",
buttonLabelSubCopy: "Super duper surprise :)",
screenReaderOnlyText: "Tests are fun!",
},
},
});
// Assert
const content = wrapper.find(".list-button-horizontal-content");
const screenReaderOnlyText = wrapper.find(".sr-only");
expect(content.isVisible()).toBe(true);
expect(screenReaderOnlyText.exists()).toBe(true);
expect(screenReaderOnlyText.text()).toContain("Tests are fun!");
});
}); });
it("Should return input type radio if isMultiSelect is false or not specified", async () => {
// Act
const { wrapper } = setupMocks({
mockData: {
propsData: {
isMultiSelect: false,
},
},
});
// Assert
const input = wrapper.find("input");
expect(input.attributes().type).toEqual("radio");
});
// TODO KO
it.skip("Should emit button value on click", async () => {
// Act
const { wrapper } = setupMocks({
mockData: {
propsData: {
isRadioHorizontal: true,
buttonLabel: "Windshield",
value: "List Card Checkbox",
groupID: "radio-demo-1",
groupName: "radio 1",
buttonImage: "windshield-damage.svg",
isRequired: true,
isWide: false,
modelValue: ["List Card Checkbox"],
buttonID: "list-card-id",
},
},
});
// Act
wrapper.vm.handleAnswerChange("test");
await wrapper.vm.$nextTick();
// Assert
expect(wrapper.emitted()["change"][0]).toEqual(["test"]);
});
});
describe("styling/UI", () => {
it("Should return screen reader text", async () => {
// Act
const { wrapper } = setupMocks({
mockData: {
propsData: {
screenReaderOnlyText: "Screen Reader Only Text",
},
},
});
// Assert
const paragraph = wrapper.find("span.sr-only");
expect(paragraph.text()).toEqual("Screen Reader Only Text");
});
it("Should return text alignment class", async () => {
// Act
const { wrapper } = setupMocks({
mockData: {
propsData: {
textPosition: "text-center",
},
},
});
// Assert
const paragraph = wrapper.find("span.m-0");
expect(paragraph.attributes("class")).toContain("text-center");
});
it("Should return aria-required state", async () => {
// Act
const { wrapper } = setupMocks({
mockData: {
propsData: {
isRequired: true,
},
},
});
// Assert
const input = wrapper.find("input");
expect(input.attributes()["aria-required"]).toEqual("true");
});
// it("is cash or insurance button => has 'radio-fancy' class", () => {
// // Arrange/Act
// const { wrapper } = setupMocks({
// mockData: {
// propsData: {
// isCashOrInsurance: true,
// },
// },
// });
// // Assert
// const label = wrapper.find("label");
// expect(label.classes()).toContain("radio-fancy");
// });
test("has buttonLabel => displays buttonLabel", () => {
// Arrange/Act
const { wrapper } = setupMocks({
mockData: {
propsData: {
buttonLabel: "Surprise!",
},
},
});
// Assert
const content = wrapper.find(".list-button-horizontal-content");
expect(content.isVisible()).toBe(true);
expect(content.text()).toContain("Surprise!");
});
test("has buttonLabelSubCopy => displays buttonLabelSubCopy", () => {
// Arrange/Act
const { wrapper } = setupMocks({
mockData: {
propsData: {
buttonLabel: "Surprise!",
buttonLabelSubCopy: "Super duper surprise :)",
},
},
});
// Assert
const content = wrapper.find(".list-button-horizontal-content");
expect(content.isVisible()).toBe(true);
expect(content.text()).toContain("Super duper surprise :)");
});
test("has screenReaderOnlyText => displays screenReaderOnlyText", () => {
// Arrange/Act
const { wrapper } = setupMocks({
mockData: {
propsData: {
buttonLabel: "Surprise!",
buttonLabelSubCopy: "Super duper surprise :)",
screenReaderOnlyText: "Tests are fun!"
},
},
});
// Assert
const content = wrapper.find(".list-button-horizontal-content");
const screenReaderOnlyText = wrapper.find(".sr-only");
expect(content.isVisible()).toBe(true);
expect(screenReaderOnlyText.exists()).toBe(true);
expect(screenReaderOnlyText.text()).toContain("Tests are fun!");
});
});
}); });
function setupMocks({ mockData }) { function setupMocks({ mockData }) {
const wrapper = mount(listButtonHorizontal, { const wrapper = mount(listButtonHorizontal, {
...mockData, ...mockData,
propsData: { propsData: {
...mockData.propsData, ...mockData.propsData,
groupName: "my-group", groupName: "my-group",
modelValue: mockData.propsData?.isMultiSelect ? ["5"] : "5", modelValue: mockData.propsData?.isMultiSelect ? ["5"] : "5",
value: mockData.propsData?.isMultiSelect ? ["4"] : "4" value: mockData.propsData?.isMultiSelect ? ["4"] : "4",
}, },
mixins: [inputButtonWrapperMixin], mixins: [inputButtonWrapperMixin],
}); });
return { wrapper }; return { wrapper };
} }

View file

@ -1,262 +1,304 @@
import { shallowMount, mount } from "@vue/test-utils"; import { mount } from "@vue/test-utils";
import listButton from "./list-button"; import listButton from "./list-button";
import { nextTick } from "vue";
import { GaActions } from "@/constants/analytics"; import { GaActions } from "@/constants/analytics";
import inputButtonWrapperMixin from "@/mixins/input-button-wrapper-mixin"; import inputButtonWrapperMixin from "@/mixins/input-button-wrapper-mixin";
// TODO KO describe("list-button.vue", () => {
describe.skip("list-button.vue", () => { describe("loader", () => {
describe("loader", () => { it("selectingInitiatesLoad is true and answer is changed => show the loader", async () => {
it("selectingInitiatesLoad is true and answer is changed => show the loader", async () => { // Act
// Act const { wrapper } = setupMocks({
const { wrapper } = setupMocks({ mockData: {
mockData: { global: {
global: { mocks: {
mocks: { $route: { query: { fmgPage: "page-name" } },
$route: { query: { fmgPage: "page-name" } }, GaActions: GaActions,
GaActions: GaActions, pushEventToGA: jest.fn(),
pushEventToGA: jest.fn(), },
}, },
}, propsData: {
propsData: { selectingInitiatesLoad: true,
selectingInitiatesLoad: true, },
}, },
}, });
});
// Act // Act
wrapper.vm.handleAnswerChange("something"); wrapper.vm.selectedValue = "something";
await wrapper.vm.$nextTick(); await wrapper.vm.$nextTick();
// Assert // Assert
const loader = wrapper.findComponent({ name: "loader" }); const loader = wrapper.findComponent({ name: "loader" });
expect(loader.exists()).toBe(true); expect(loader.exists()).toBe(true);
});
it("Should return loader color", async () => {
// Arrange
const { wrapper } = setupMocks({
mockData: {
global: {
mocks: {
$route: { query: { fmgPage: "page-name" } },
GaActions: GaActions,
pushEventToGA: jest.fn(),
},
},
propsData: {
loaderColor: "blue",
selectingInitiatesLoad: true,
},
},
});
// Act
wrapper.vm.selectedValue = "something";
await wrapper.vm.$nextTick();
// Assert
const loader = wrapper.findComponent({ name: "loader" });
expect(loader.attributes("class")).toContain("blue");
});
it("Should return loader position", async () => {
// Act
const { wrapper } = setupMocks({
mockData: {
global: {
mocks: {
$route: { query: { fmgPage: "page-name" } },
GaActions: GaActions,
pushEventToGA: jest.fn(),
},
},
propsData: {
loaderPosition: "right",
selectingInitiatesLoad: true,
},
},
});
// Act
wrapper.vm.selectedValue = "something";
await wrapper.vm.$nextTick();
// Assert
const loader = wrapper.findComponent({ name: "loader" });
expect(loader.attributes("class")).toContain("right");
});
}); });
it("Should return loader color", async () => { describe("baseInputButton checks", () => {
// Act it("Should return input type checkbox if isMultiSelect is true", async () => {
const { wrapper } = setupMocks({ // Act
mockData: { const { wrapper } = setupMocks({
global: { mockData: {
mocks: { propsData: {
$route: { query: { fmgPage: "page-name" } }, isMultiSelect: true,
GaActions: GaActions, },
pushEventToGA: jest.fn(), },
}, });
},
propsData: {
loaderColor: "blue",
selectingInitiatesLoad: true,
},
},
});
// Act // Assert
wrapper.vm.handleAnswerChange("something"); const input = wrapper.find("input");
await nextTick();
// Assert expect(input.attributes().type).toEqual("checkbox");
const loader = wrapper.findComponent({ name: "loader" }); });
expect(loader.attributes("class")).toContain("blue");
it("Should return input type radio if isMultiSelect is false or not specified", async () => {
// Act
const { wrapper } = setupMocks({
mockData: {
propsData: {
isMultiSelect: false,
},
},
});
// Assert
const input = wrapper.find("input");
expect(input.attributes().type).toEqual("radio");
});
it("(Radio) Should emit button value on selectedValue change", async () => {
// Act
const { wrapper } = setupMocks({
mockData: {
propsData: {
isRadioHorizontal: true,
buttonLabel: "Windshield",
value: "List Card Checkbox",
groupID: "radio-demo-1",
groupName: "radio1",
buttonImage: "windshield-damage.svg",
isRequired: true,
isWide: false,
modelValue: "List Card Checkbox",
buttonID: "list-card-id",
},
},
});
// Act
wrapper.vm.selectedValue = "test";
// Assert
expect(wrapper.emitted()["update:modelValue"][0][0]).toEqual("test");
});
it("(Checkbox) Should emit button value on selectedValue change", async () => {
// Act
const { wrapper } = setupMocks({
mockData: {
propsData: {
isRadioHorizontal: true,
buttonLabel: "Windshield",
value: "List Card Checkbox",
groupID: "radio-demo-1",
groupName: "radio 1",
buttonImage: "windshield-damage.svg",
isRequired: true,
isWide: false,
modelValue: "List Card Checkbox",
buttonID: "list-card-id",
isMultiSelect: true,
},
},
});
// Act
wrapper.vm.selectedValue = ["test"];
// Assert
expect(wrapper.emitted()["update:modelValue"][0][0]).toEqual(["test"]);
});
}); });
it("Should return loader position", async () => { describe("styling/UI", () => {
// Act test("has buttonLabel => displays buttonLabel", () => {
const { wrapper } = setupMocks({ // Arrange/Act
mockData: { const { wrapper } = setupMocks({
global: { mockData: {
mocks: { propsData: {
$route: { query: { fmgPage: "page-name" } }, buttonLabel: "Surprise!",
GaActions: GaActions, modelValue: "",
pushEventToGA: jest.fn(), groupName: "groupName",
}, value: "myValue"
}, },
propsData: { },
loaderPosition: "right", });
selectingInitiatesLoad: true,
},
},
});
// Act // Assert
wrapper.vm.handleAnswerChange("test"); const content = wrapper.find(".list-button-content");
await nextTick(); expect(content.isVisible()).toBe(true);
expect(content.text()).toContain("Surprise!");
});
// Assert test("has buttonLabelSubCopy => displays buttonLabelSubCopy", () => {
const loader = wrapper.findComponent({ name: "loader" }); // Arrange/Act
expect(loader.attributes("class")).toContain("right"); const { wrapper } = setupMocks({
mockData: {
propsData: {
buttonLabel: "Surprise!",
buttonLabelSubCopy: "Super duper surprise :)",
modelValue: "",
groupName: "groupName",
value: "myValue"
},
},
});
// Assert
const content = wrapper.find(".list-button-content");
expect(content.isVisible()).toBe(true);
expect(content.text()).toContain("Super duper surprise :)");
});
test("has screenReaderOnlyText => displays screenReaderOnlyText", () => {
// Arrange/Act
const { wrapper } = setupMocks({
mockData: {
propsData: {
buttonLabel: "Surprise!",
buttonLabelSubCopy: "Super duper surprise :)",
screenReaderOnlyText: "Tests are fun!",
modelValue: "",
groupName: "groupName",
value: "myValue"
},
},
});
// Assert
const content = wrapper.find(".list-button-content");
const screenReaderOnlyText = wrapper.find(".sr-only");
expect(content.isVisible()).toBe(true);
expect(screenReaderOnlyText.exists()).toBe(true);
expect(screenReaderOnlyText.text()).toContain("Tests are fun!");
});
it("Should return screen reader text", async () => {
// Act
const { wrapper } = setupMocks({
mockData: {
propsData: {
screenReaderOnlyText: "Screen Reader Only Text",
modelValue: "",
groupName: "groupName",
value: "myValue"
},
},
});
// Assert
const paragraph = wrapper.find("span.sr-only");
expect(paragraph.text()).toEqual("Screen Reader Only Text");
});
it("Should return text alignment class", async () => {
// Act
const { wrapper } = setupMocks({
mockData: {
propsData: {
textPosition: "text-center",
modelValue: "",
groupName: "groupName",
value: "myValue"
},
},
});
// Assert
const paragraph = wrapper.find("span.m-0");
expect(paragraph.attributes("class")).toContain("text-center");
});
it("Should return aria-required state", async () => {
// Act
const { wrapper } = setupMocks({
mockData: {
propsData: {
isRequired: true,
groupName: "groupName",
modelValue: "",
value: "myValue",
},
},
});
// Assert
const input = wrapper.find("input");
expect(input.attributes()["aria-required"]).toEqual("true");
});
}); });
});
describe("baseInputButton checks", () => {
it("Should return input type checkbox if isMultiSelect is true", async () => {
// Act
const { wrapper } = setupMocks({
mockData: {
propsData: {
isMultiSelect: true,
},
},
});
// Assert
const input = wrapper.find("input");
expect(input.attributes().type).toEqual("checkbox");
});
it("Should return input type radio if isMultiSelect is false or not specified", async () => {
// Act
const { wrapper } = setupMocks({
mockData: {
propsData: {
isMultiSelect: false,
},
},
});
// Assert
const input = wrapper.find("input");
expect(input.attributes().type).toEqual("radio");
});
it("Should emit button value on click", async () => {
// Act
const { wrapper } = setupMocks({
mockData: {
propsData: {
isRadioHorizontal: true,
buttonLabel: "Windshield",
value: "List Card Checkbox",
groupID: "radio-demo-1",
groupName: "radio 1",
buttonImage: "windshield-damage.svg",
isRequired: true,
isWide: false,
modelValue: ["List Card Checkbox"],
buttonID: "list-card-id",
},
},
});
// Act
wrapper.vm.handleAnswerChange("test");
await wrapper.vm.$nextTick();
// Assert
expect(wrapper.emitted()["change"][0]).toEqual(["test"]);
});
});
describe("styling/UI", () => {
test("has buttonLabel => displays buttonLabel", () => {
// Arrange/Act
const { wrapper } = setupMocks({
mockData: {
propsData: {
buttonLabel: "Surprise!",
},
},
});
// Assert
const content = wrapper.find(".list-button-content");
expect(content.isVisible()).toBe(true);
expect(content.text()).toContain("Surprise!");
});
test("has buttonLabelSubCopy => displays buttonLabelSubCopy", () => {
// Arrange/Act
const { wrapper } = setupMocks({
mockData: {
propsData: {
buttonLabel: "Surprise!",
buttonLabelSubCopy: "Super duper surprise :)",
},
},
});
// Assert
const content = wrapper.find(".list-button-content");
expect(content.isVisible()).toBe(true);
expect(content.text()).toContain("Super duper surprise :)");
});
test("has screenReaderOnlyText => displays screenReaderOnlyText", () => {
// Arrange/Act
const { wrapper } = setupMocks({
mockData: {
propsData: {
buttonLabel: "Surprise!",
buttonLabelSubCopy: "Super duper surprise :)",
screenReaderOnlyText: "Tests are fun!",
},
},
});
// Assert
const content = wrapper.find(".list-button-content");
const screenReaderOnlyText = wrapper.find(".sr-only");
expect(content.isVisible()).toBe(true);
expect(screenReaderOnlyText.exists()).toBe(true);
expect(screenReaderOnlyText.text()).toContain("Tests are fun!");
});
it("Should return screen reader text", async () => {
// Act
const { wrapper } = setupMocks({
mockData: {
propsData: {
screenReaderOnlyText: "Screen Reader Only Text",
},
},
});
// Assert
const paragraph = wrapper.find("span.sr-only");
expect(paragraph.text()).toEqual("Screen Reader Only Text");
});
it("Should return text alignment class", async () => {
// Act
const { wrapper } = setupMocks({
mockData: {
propsData: {
textPosition: "text-center",
},
},
});
// Assert
const paragraph = wrapper.find("span.m-0");
expect(paragraph.attributes("class")).toContain("text-center");
});
it("Should return aria-required state", async () => {
// Act
const { wrapper } = setupMocks({
mockData: {
propsData: {
isRequired: true,
},
},
});
// Assert
const input = wrapper.find("input");
expect(input.attributes()["aria-required"]).toEqual("true");
});
});
}); });
function setupMocks({ mockData }) { function setupMocks({ mockData }) {
const wrapper = mount(listButton, { const wrapper = mount(listButton, {
...mockData, ...mockData,
mixins: [inputButtonWrapperMixin], mixins: [inputButtonWrapperMixin],
}); });
return { wrapper }; return { wrapper };
} }