Merge pull request #763 from Safelite/feature/CSR-762-GA
DO NOT MERGE - For viewing purposes
This commit is contained in:
commit
39d922fd4e
31 changed files with 1803 additions and 1103 deletions
|
|
@ -1,4 +1,4 @@
|
||||||
{
|
{
|
||||||
"tabWidth": 2,
|
"tabWidth": 4,
|
||||||
"bracketSameLine": true
|
"bracketSameLine": true
|
||||||
}
|
}
|
||||||
|
|
@ -28,8 +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: {
|
||||||
// TODO KO
|
statements: 85,
|
||||||
statements: 55,
|
|
||||||
// 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
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
71
src/App.vue
71
src/App.vue
|
|
@ -1,16 +1,65 @@
|
||||||
<template>
|
<template>
|
||||||
<router-view v-slot="{ Component }">
|
<router-view v-slot="{ Component }">
|
||||||
<transition :duration="{ enter: 200, leave: 200 }" name="route-fade" mode="out-in">
|
<transition
|
||||||
<!-- The above durations should be kept in sync with the global css class "fade-on-route-transition" -->
|
:duration="{ enter: 200, leave: 200 }"
|
||||||
<component :is="Component" />
|
name="route-fade"
|
||||||
</transition>
|
mode="out-in">
|
||||||
</router-view>
|
<!-- The above durations should be kept in sync with the global css class "fade-on-route-transition" -->
|
||||||
|
<component :is="Component" @focusin="handleChildFocus" />
|
||||||
|
</transition>
|
||||||
|
</router-view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// TODO KO glass-part-question has nested button questions
|
||||||
|
// TODO KO selectedValues - make consistent for checkbox and radio if possible
|
||||||
|
export default {
|
||||||
|
name: "app",
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
lastFocusedInputGroupName: "",
|
||||||
|
onFocusCallback: null,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleChildFocus(e) {
|
||||||
|
const targetType = e.target.type;
|
||||||
|
if (targetType !== "radio" && targetType !== "checkbox") {
|
||||||
|
this.handleInputFocus({
|
||||||
|
groupName: null,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handleInputFocus(e) {
|
||||||
|
if (
|
||||||
|
e &&
|
||||||
|
this.lastFocusedInputGroupName !== e.groupName &&
|
||||||
|
this.onFocusCallback
|
||||||
|
) {
|
||||||
|
this.onFocusCallback();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handleInputBlur(e) {
|
||||||
|
if (e) {
|
||||||
|
this.lastFocusedInputGroupName = e.groupName;
|
||||||
|
this.onFocusCallback = e.onFocusCallback;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
$route: {
|
||||||
|
handler() {
|
||||||
|
this.lastFocusedInputGroup = null;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@import "./node_modules/bootstrap/scss/bootstrap";
|
@import "./node_modules/bootstrap/scss/bootstrap";
|
||||||
@import "@/styles/common-styles.scss";
|
@import "@/styles/common-styles.scss";
|
||||||
@import "@/styles/common-typography-styles.scss";
|
@import "@/styles/common-typography-styles.scss";
|
||||||
@import "@/styles/common-error-styles.scss";
|
@import "@/styles/common-error-styles.scss";
|
||||||
@import "@/styles/common-animations.scss";
|
@import "@/styles/common-animations.scss";
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,539 @@
|
||||||
|
import { shallowMount, mount } from "@vue/test-utils";
|
||||||
|
import baseInputButton from "./base-input-button";
|
||||||
|
|
||||||
|
describe("baseInputButton.vue", () => {
|
||||||
|
describe("general", () => {
|
||||||
|
describe("checkbox", () => {
|
||||||
|
test("isMultiSelect => baseInputButton is a checkbox", () => {
|
||||||
|
// Arrange/Act
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
mockData: {
|
||||||
|
propsData: {
|
||||||
|
isMultiSelect: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
const inputElement = wrapper.find("input");
|
||||||
|
expect(inputElement.attributes().type).toEqual("checkbox");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("radio", () => {
|
||||||
|
test("!isMultiSelect => baseInputButton is a radio button", () => {
|
||||||
|
// Arrange/Act
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
mockData: {
|
||||||
|
propsData: {
|
||||||
|
isMultiSelect: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
const inputElement = wrapper.find("input");
|
||||||
|
expect(inputElement.attributes().type).toEqual("radio");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// tests in here should be test.each
|
||||||
|
describe("shared", () => {
|
||||||
|
const isMultiSelectOptions = [true, false];
|
||||||
|
test.each(isMultiSelectOptions)("groupName", (isMultiSelect) => {
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
mockData: {
|
||||||
|
propsData: {
|
||||||
|
groupName: "boogly",
|
||||||
|
isMultiSelect: isMultiSelect,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
const inputElement = wrapper.find("input");
|
||||||
|
const inputElementAttributes = inputElement.attributes();
|
||||||
|
expect(inputElementAttributes.name).toEqual("boogly");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("mouse clicks", () => {
|
||||||
|
describe("checkbox", () => {
|
||||||
|
test("clicked => correct event and value are emitted", async () => {
|
||||||
|
// Arrange
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
mockData: {
|
||||||
|
propsData: {
|
||||||
|
isMultiSelect: true,
|
||||||
|
value: "X",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await wrapper.trigger("mousedown.left");
|
||||||
|
await wrapper.trigger("click");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(wrapper.emitted()["inputButtonClicked"][0][0]).toEqual([
|
||||||
|
"X",
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("radio", () => {
|
||||||
|
test("clicked => correct event and value are emitted", async () => {
|
||||||
|
// Arrange
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
mockData: {
|
||||||
|
propsData: {
|
||||||
|
isMultiSelect: false,
|
||||||
|
value: "X",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await wrapper.trigger("mousedown.left");
|
||||||
|
await wrapper.trigger("click");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(wrapper.emitted()["inputButtonClicked"][0][0]).toEqual(
|
||||||
|
"X"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("keyboard navigation and events", () => {
|
||||||
|
describe("checkbox", () => {
|
||||||
|
test.todo(
|
||||||
|
"focus on a checkbox => inputButtonClicked is not emitted"
|
||||||
|
);
|
||||||
|
|
||||||
|
test.todo(
|
||||||
|
"blur from a checkbox => inputButtonClicked is not emitted"
|
||||||
|
);
|
||||||
|
|
||||||
|
test("change event fired from checkbox => inputButtonClicked is emitted with correct value", async () => {
|
||||||
|
// Arrange
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
mockData: {
|
||||||
|
propsData: {
|
||||||
|
isMultiSelect: true,
|
||||||
|
value: "Hi",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const input = wrapper.find("input");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await input.trigger("change");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(wrapper.emitted()["inputButtonClicked"][0][0]).toEqual([
|
||||||
|
"Hi",
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("focus and click space on a checkbox => inputButtonClicked is not emitted", async () => {
|
||||||
|
// Arrange
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
mockData: {
|
||||||
|
propsData: {
|
||||||
|
isMultiSelect: true,
|
||||||
|
value: "Hi",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const input = wrapper.find("input");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await input.trigger("keypress", { key: "space" });
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(wrapper.emitted()).not.toHaveProperty(
|
||||||
|
"inputButtonClicked"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("focus and click enter on a checkbox => inputButtonClicked is emitted with correct value", async () => {
|
||||||
|
// Arrange
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
mockData: {
|
||||||
|
propsData: {
|
||||||
|
isMultiSelect: true,
|
||||||
|
value: "Hi",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const input = wrapper.find("input");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await input.trigger("keypress", { key: "enter" });
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(wrapper.emitted()["inputButtonClicked"][0][0]).toEqual([
|
||||||
|
"Hi",
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("radio", () => {
|
||||||
|
test.todo(
|
||||||
|
"focus on a radio button => inputButtonClicked is not emitted"
|
||||||
|
);
|
||||||
|
|
||||||
|
test.todo(
|
||||||
|
"blur from a radio button => inputButtonClicked is not emitted"
|
||||||
|
);
|
||||||
|
|
||||||
|
test("focus and click space on a radio button => inputButtonClicked is emitted with correct value", async () => {
|
||||||
|
// Arrange
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
mockData: {
|
||||||
|
propsData: {
|
||||||
|
isMultiSelect: false,
|
||||||
|
value: "Hi",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const input = wrapper.find("input");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await input.trigger("keypress", { key: "space" });
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(wrapper.emitted()).toHaveProperty("inputButtonClicked");
|
||||||
|
expect(wrapper.emitted()["inputButtonClicked"][0][0]).toEqual(
|
||||||
|
"Hi"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("focus and click enter on a radio button => inputButtonClicked is emitted with correct value", async () => {
|
||||||
|
// Arrange
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
mockData: {
|
||||||
|
propsData: {
|
||||||
|
isMultiSelect: false,
|
||||||
|
value: "Hi",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const input = wrapper.find("input");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await input.trigger("keypress", { key: "enter" });
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(wrapper.emitted()).toHaveProperty("inputButtonClicked");
|
||||||
|
expect(wrapper.emitted()["inputButtonClicked"][0][0]).toEqual(
|
||||||
|
"Hi"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("methods", () => {
|
||||||
|
describe("handleEventAction", () => {});
|
||||||
|
|
||||||
|
describe("handleSelectionChange", () => {
|
||||||
|
test.todo("handleChange is called with valueToEmit");
|
||||||
|
|
||||||
|
describe("checkbox", () => {
|
||||||
|
test.todo("modelValue is null => valueToEmit is correct value");
|
||||||
|
|
||||||
|
test.todo(
|
||||||
|
"modelValue is undefined => valueToEmit is correct value"
|
||||||
|
);
|
||||||
|
test.todo(
|
||||||
|
"modelValue is empty => valueToEmit is correct value"
|
||||||
|
);
|
||||||
|
|
||||||
|
test.todo(
|
||||||
|
"modelValue is not empty and does not contain this button's value => valueToEmit is correct value"
|
||||||
|
);
|
||||||
|
test.todo(
|
||||||
|
"modelValue is not empty and does contain this button's value => valueToEmit is correct value"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("radio", () => {});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("handleClick", () => {
|
||||||
|
test.todo("handleSelectChange is also called");
|
||||||
|
|
||||||
|
test.todo("inputButtonClicked is emitted with valueToEmit");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("computed", () => {
|
||||||
|
describe("isChecked", () => {
|
||||||
|
describe("checkbox", () => {
|
||||||
|
const falsyModelValues = [[], null, undefined];
|
||||||
|
test.each(falsyModelValues)(
|
||||||
|
"modelValue is falsy/empty => checkbox isn't checked",
|
||||||
|
(modelValue) => {
|
||||||
|
// Arrange/Act
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
mockData: {
|
||||||
|
propsData: {
|
||||||
|
isMultiSelect: true,
|
||||||
|
modelValue,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
const inputElement = wrapper.find("input");
|
||||||
|
expect(wrapper.vm.isChecked).toEqual(false);
|
||||||
|
expect(inputElement.element.checked).toBe(false);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
test("modelValue doesn't contain this button's value => checkbox isn't checked", async () => {
|
||||||
|
// Arrange/Act
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
mockData: {
|
||||||
|
propsData: {
|
||||||
|
isMultiSelect: true,
|
||||||
|
modelValue: ["Aaa", "Bbb", "Ccc"],
|
||||||
|
value: "Ddd",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await wrapper.vm.$nextTick();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
const inputElement = wrapper.find("input");
|
||||||
|
expect(wrapper.vm.isChecked).toEqual(false);
|
||||||
|
expect(inputElement.element.checked).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("modelValue contains this button's value => checkbox is checked", () => {
|
||||||
|
// Arrange/Act
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
mockData: {
|
||||||
|
propsData: {
|
||||||
|
isMultiSelect: true,
|
||||||
|
modelValue: ["Aaa", "Bbb", "Ddd", "Ccc"],
|
||||||
|
value: "Ddd",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
const inputElement = wrapper.find("input");
|
||||||
|
expect(wrapper.vm.isChecked).toEqual(true);
|
||||||
|
expect(inputElement.element.checked).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("radio", () => {
|
||||||
|
const falsyModelValues = ["", null, undefined, []];
|
||||||
|
test.each(falsyModelValues)(
|
||||||
|
"modelValue is falsy/empty => radio button isn't checked",
|
||||||
|
(modelValue) => {
|
||||||
|
// Arrange/Act
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
mockData: {
|
||||||
|
propsData: {
|
||||||
|
isMultiSelect: false,
|
||||||
|
modelValue,
|
||||||
|
value: "Aaa",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
const inputElement = wrapper.find("input");
|
||||||
|
expect(wrapper.vm.isChecked).toEqual(false);
|
||||||
|
expect(inputElement.element.checked).toBe(false);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
test("modelValue equals this button's value => radio button is checked", () => {
|
||||||
|
// Arrange/Act
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
mockData: {
|
||||||
|
propsData: {
|
||||||
|
isMultiSelect: false,
|
||||||
|
modelValue: "Ddd",
|
||||||
|
value: "Ddd",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
const inputElement = wrapper.find("input");
|
||||||
|
expect(wrapper.vm.isChecked).toEqual(true);
|
||||||
|
expect(inputElement.element.checked).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("modelValue doesn't equal this button's value => radio button isn't checked", () => {
|
||||||
|
// Arrange/Act
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
mockData: {
|
||||||
|
propsData: {
|
||||||
|
isMultiSelect: false,
|
||||||
|
modelValue: "Aaa",
|
||||||
|
value: "Ddd",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
const inputElement = wrapper.find("input");
|
||||||
|
expect(wrapper.vm.isChecked).toEqual(false);
|
||||||
|
expect(inputElement.element.checked).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("buttonId", () => {
|
||||||
|
test("groupName and value combo yield correct id for input button with string value", () => {
|
||||||
|
// Arrange/Act
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
mockData: {
|
||||||
|
propsData: {
|
||||||
|
groupName: "my test-name",
|
||||||
|
value: "Aaa-BBB CcC",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
const inputElement = wrapper.find("input");
|
||||||
|
expect(wrapper.vm.buttonId).toBe("my-test-name-Aaa-BBB-CcC");
|
||||||
|
expect(inputElement.attributes().id).toBe(
|
||||||
|
"my-test-name-Aaa-BBB-CcC"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("groupName and value combo yield correct id for input button with number value", () => {
|
||||||
|
// Arrange/Act
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
mockData: {
|
||||||
|
propsData: {
|
||||||
|
groupName: "my test-name",
|
||||||
|
value: 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
const inputElement = wrapper.find("input");
|
||||||
|
expect(wrapper.vm.buttonId).toBe("my-test-name-2");
|
||||||
|
expect(inputElement.attributes().id).toBe("my-test-name-2");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("inputType", () => {
|
||||||
|
test("isMultiSelect is true => inputType is 'checkbox'", () => {
|
||||||
|
// Arrange/Act
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
mockData: {
|
||||||
|
propsData: {
|
||||||
|
isMultiSelect: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
const inputElement = wrapper.find("input");
|
||||||
|
expect(wrapper.vm.inputType).toEqual("checkbox");
|
||||||
|
expect(inputElement.attributes().type).toBe("checkbox");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("isMultiSelect is false => inputType is 'radio'", () => {
|
||||||
|
// Arrange/Act
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
mockData: {
|
||||||
|
propsData: {
|
||||||
|
isMultiSelect: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
const inputElement = wrapper.find("input");
|
||||||
|
expect(wrapper.vm.inputType).toEqual("radio");
|
||||||
|
expect(inputElement.attributes().type).toBe("radio");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO KO look at how I tested groups of these in SFA (making sure selecting one radio changes the value, etc, that this acts like a regular input aside from a different emitted event)
|
||||||
|
|
||||||
|
function setupMocks({ mockData = {}, shouldShallowMount = true }) {
|
||||||
|
const baseInputButtonWrapper = {
|
||||||
|
components: { baseInputButton },
|
||||||
|
template: '<baseInputButton v-model="myValue" />',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
myValue: "",
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const mountMockData = {
|
||||||
|
...mockData,
|
||||||
|
propsData: {
|
||||||
|
// to get rid of some annoying warnings
|
||||||
|
groupName: "groupName",
|
||||||
|
modelValue: mockData.propsData?.isMultiSelect ? [] : "",
|
||||||
|
value: "5",
|
||||||
|
setLastValuePushedToGa: () => {},
|
||||||
|
// should override the above if they exist
|
||||||
|
...mockData.propsData,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = shouldShallowMount
|
||||||
|
? shallowMount(baseInputButton, mountMockData)
|
||||||
|
: mount(baseInputButton, mountMockData);
|
||||||
|
|
||||||
|
wrapper.vm.pushEventToGA = jest.fn();
|
||||||
|
wrapper.vm.$route = {
|
||||||
|
query: {},
|
||||||
|
};
|
||||||
|
wrapper.vm.GaActions = {}
|
||||||
|
|
||||||
|
return { wrapper };
|
||||||
|
}
|
||||||
|
|
||||||
|
function setupBaseInputButtonWrapper({ mockData = {} }) {
|
||||||
|
const baseInputButtonWrapper = {
|
||||||
|
components: { baseInputButton },
|
||||||
|
template:
|
||||||
|
'<div><baseInputButton v-model="myValue" groupName="myGroupName" value="X" :isMultiSelect="isMultiSelect" /></div>',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
myValue: "",
|
||||||
|
isMultiSelect: mockData.isMultiSelect,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
// const parentComponent = mount({
|
||||||
|
// data() {
|
||||||
|
// return {
|
||||||
|
// value: "value1",
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// template: '<div><baseInputButton v-model="value" value="value1" /><baseInputButton v-model="value" value="value2" /></div>',
|
||||||
|
// components: { baseInputButton }
|
||||||
|
// })
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(baseInputButtonWrapper, {});
|
||||||
|
|
||||||
|
return { wrapper };
|
||||||
|
}
|
||||||
|
|
@ -2,8 +2,9 @@
|
||||||
<label
|
<label
|
||||||
:class="[buttonWrapperClasses, { 'has-error': errors.length > 0 }]"
|
:class="[buttonWrapperClasses, { 'has-error': errors.length > 0 }]"
|
||||||
:for="buttonId"
|
:for="buttonId"
|
||||||
@mousedown.left="handleEventAction('click', $event)"
|
@focusin="handleFocus"
|
||||||
@keyup="handleKeyboardNavigation">
|
@focusout="handleBlur"
|
||||||
|
@mousedown.left="handleEventAction('click', $event)">
|
||||||
<input
|
<input
|
||||||
:type="inputType"
|
:type="inputType"
|
||||||
:id="buttonId"
|
:id="buttonId"
|
||||||
|
|
@ -13,7 +14,6 @@
|
||||||
:aria-required="isRequired"
|
:aria-required="isRequired"
|
||||||
:value="value"
|
:value="value"
|
||||||
:checked="isChecked"
|
:checked="isChecked"
|
||||||
@blur="handleBlur"
|
|
||||||
@keypress.space="handleEventAction('space', $event)"
|
@keypress.space="handleEventAction('space', $event)"
|
||||||
@keypress.enter="handleEventAction('enter', $event)"
|
@keypress.enter="handleEventAction('enter', $event)"
|
||||||
@change="handleEventAction('change', $event)" />
|
@change="handleEventAction('change', $event)" />
|
||||||
|
|
@ -23,18 +23,20 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { queryStrings } from "@/constants/query-strings";
|
|
||||||
import { useField } from "vee-validate";
|
import { useField } from "vee-validate";
|
||||||
import { toRef } from "vue";
|
import { toRef } from "vue";
|
||||||
|
import { queryStrings } from "@/constants/query-strings";
|
||||||
|
import inputButtonWrapperMixin from "../../mixins/input-button-wrapper-mixin";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "base-input-button",
|
name: "base-input-button",
|
||||||
emits: ["change"],
|
emits: ["change", "inputButtonClicked"],
|
||||||
model: {
|
model: {
|
||||||
prop: "modelValue",
|
prop: "modelValue",
|
||||||
event: "change",
|
event: "change",
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
|
// ...inputButtonWrapperMixin.props
|
||||||
value: {
|
value: {
|
||||||
type: [String, Number],
|
type: [String, Number],
|
||||||
required: true,
|
required: true,
|
||||||
|
|
@ -60,6 +62,9 @@ export default {
|
||||||
default: true,
|
default: true,
|
||||||
},
|
},
|
||||||
isRequired: Boolean,
|
isRequired: Boolean,
|
||||||
|
lastValuePushedToGa: [String, Number],
|
||||||
|
setLastValuePushedToGa: Function,
|
||||||
|
shouldPushClickEventToGAOnMount: Boolean,
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
|
@ -68,36 +73,37 @@ export default {
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
if (this.isChecked) {
|
if (this.isChecked) {
|
||||||
this.handleChange(this.modelValue);
|
if (this.shouldPushClickEventToGAOnMount) {
|
||||||
|
this.handleEventAction(this.eventTypes.MOUNT)
|
||||||
|
} else {
|
||||||
|
this.handleChange(this.modelValue);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
handleEventAction(eventType, e) {
|
handleEventAction(eventType, e) {
|
||||||
const eventTypes = {
|
|
||||||
CHANGE: "change",
|
|
||||||
ENTER: "enter",
|
|
||||||
SPACE: "space",
|
|
||||||
CLICK: "click",
|
|
||||||
};
|
|
||||||
|
|
||||||
if (this.isMultiSelect) {
|
if (this.isMultiSelect) {
|
||||||
switch (eventType) {
|
switch (eventType) {
|
||||||
case eventTypes.ENTER:
|
case this.eventTypes.ENTER:
|
||||||
case eventTypes.CHANGE:
|
case this.eventTypes.CHANGE:
|
||||||
this.handleClick(e);
|
this.handleClick(e);
|
||||||
window.lastFocusedInputGroup = this.groupName;
|
this.handlePushClickEventToGACheck(
|
||||||
this.pushClickEventToGA();
|
this.eventTypes.CLICK
|
||||||
|
);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
switch (eventType) {
|
switch (eventType) {
|
||||||
case eventTypes.CLICK:
|
case this.eventTypes.CLICK:
|
||||||
case eventTypes.ENTER:
|
case this.eventTypes.ENTER:
|
||||||
case eventTypes.SPACE:
|
case this.eventTypes.SPACE:
|
||||||
|
case this.eventTypes.MOUNT:
|
||||||
this.handleClick(e);
|
this.handleClick(e);
|
||||||
this.test();
|
this.handlePushClickEventToGACheck(
|
||||||
|
this.eventTypes.CLICK
|
||||||
|
);
|
||||||
break;
|
break;
|
||||||
case eventTypes.CHANGE:
|
case this.eventTypes.CHANGE:
|
||||||
this.selectOnKeypress
|
this.selectOnKeypress
|
||||||
? this.handleClick(e)
|
? this.handleClick(e)
|
||||||
: this.handleSelectionChange(e);
|
: this.handleSelectionChange(e);
|
||||||
|
|
@ -122,21 +128,37 @@ export default {
|
||||||
this.valueToEmit = this.value;
|
this.valueToEmit = this.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
window.currentlySelectedValues =
|
|
||||||
window.currentlySelectedValues ?? {};
|
|
||||||
window.currentlySelectedValues[this.groupName] = this.value;
|
|
||||||
this.handleChange(this.valueToEmit);
|
this.handleChange(this.valueToEmit);
|
||||||
},
|
},
|
||||||
handleClick(e) {
|
handleClick(e) {
|
||||||
this.handleSelectionChange(e);
|
this.handleSelectionChange(e);
|
||||||
this.$emit("buttonClicked", this.valueToEmit);
|
this.$emit("inputButtonClicked", this.valueToEmit);
|
||||||
|
},
|
||||||
|
handleFocus() {
|
||||||
|
this.$root.handleInputFocus({
|
||||||
|
groupName: this.groupName,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
handleBlur() {
|
||||||
|
this.$root.handleInputBlur({
|
||||||
|
groupName: this.groupName,
|
||||||
|
onFocusCallback: this.handlePushClickEventToGACheck,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
handlePushClickEventToGACheck(source) {
|
||||||
|
if (source === this.eventTypes.CLICK) {
|
||||||
|
this.pushClickEventToGA();
|
||||||
|
} else {
|
||||||
|
if (
|
||||||
|
!this.isValueSelectedOnClick &&
|
||||||
|
this.isChecked &&
|
||||||
|
this.lastValuePushedToGa != this.value
|
||||||
|
) {
|
||||||
|
this.pushClickEventToGA();
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
pushClickEventToGA(value) {
|
pushClickEventToGA(value) {
|
||||||
window.firedGaClickEventValues =
|
|
||||||
window.firedGaClickEventValues ?? {};
|
|
||||||
window.firedGaClickEventValues[window.lastFocusedInputGroup] =
|
|
||||||
value ?? this.value;
|
|
||||||
|
|
||||||
this.pushEventToGA(
|
this.pushEventToGA(
|
||||||
this.$route.query[queryStrings.FMG_PAGE],
|
this.$route.query[queryStrings.FMG_PAGE],
|
||||||
this.GaActions.CLICKED,
|
this.GaActions.CLICKED,
|
||||||
|
|
@ -144,88 +166,39 @@ export default {
|
||||||
true,
|
true,
|
||||||
this.valueToLogType
|
this.valueToLogType
|
||||||
);
|
);
|
||||||
},
|
|
||||||
handleBlur() {
|
|
||||||
window.lastFocusedInputGroup = this.groupName;
|
|
||||||
window.wasLastFocusedInputMultiselect = this.isMultiSelect;
|
|
||||||
},
|
|
||||||
handleKeyboardNavigation(key) {
|
|
||||||
this.test(key);
|
|
||||||
},
|
|
||||||
test(event) {
|
|
||||||
window.firedGaClickEventValues =
|
|
||||||
window.firedGaClickEventValues ?? {};
|
|
||||||
window.currentlySelectedValues =
|
|
||||||
window.currentlySelectedValues ?? {};
|
|
||||||
|
|
||||||
const keyCode = event?.code;
|
this.setLastValuePushedToGa(this.value);
|
||||||
// Keyboard navigation
|
|
||||||
if (keyCode) {
|
|
||||||
if (
|
|
||||||
window.currentlySelectedValues &&
|
|
||||||
window.firedGaClickEventValues &&
|
|
||||||
window.lastFocusedInputGroup &&
|
|
||||||
!window.wasLastFocusedInputMultiselect &&
|
|
||||||
window.currentlySelectedValues[
|
|
||||||
window.lastFocusedInputGroup
|
|
||||||
] &&
|
|
||||||
window.firedGaClickEventValues[
|
|
||||||
window.lastFocusedInputGroup
|
|
||||||
] !=
|
|
||||||
window.currentlySelectedValues[
|
|
||||||
window.lastFocusedInputGroup
|
|
||||||
]
|
|
||||||
) {
|
|
||||||
if (keyCode === "Tab") {
|
|
||||||
this.pushClickEventToGA(
|
|
||||||
window.currentlySelectedValues[
|
|
||||||
window.lastFocusedInputGroup
|
|
||||||
]
|
|
||||||
);
|
|
||||||
} else if (keyCode?.includes("Arrow")) {
|
|
||||||
if (window.lastFocusedInputGroup != this.groupName) {
|
|
||||||
this.pushClickEventToGA(
|
|
||||||
window.currentlySelectedValues[
|
|
||||||
window.lastFocusedInputGroup
|
|
||||||
]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Radio click
|
|
||||||
window.lastFocusedInputGroup = this.groupName;
|
|
||||||
if (
|
|
||||||
window.firedGaClickEventValues[
|
|
||||||
window.lastFocusedInputGroup
|
|
||||||
] !=
|
|
||||||
window.currentlySelectedValues[window.lastFocusedInputGroup]
|
|
||||||
) {
|
|
||||||
this.pushClickEventToGA(
|
|
||||||
window.currentlySelectedValues[
|
|
||||||
window.lastFocusedInputGroup
|
|
||||||
]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
isChecked() {
|
isChecked() {
|
||||||
if (this.isMultiSelect && this.modelValue instanceof Array) {
|
if (this.isMultiSelect && this.modelValue instanceof Array) {
|
||||||
return this.modelValue.includes(this.value);
|
return this.modelValue.includes(this.value);
|
||||||
|
} else if (!this.isMultiSelect) {
|
||||||
|
return this.modelValue == this.value;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.modelValue == this.value;
|
|
||||||
},
|
},
|
||||||
inputType() {
|
inputType() {
|
||||||
return this.isMultiSelect ? "checkbox" : "radio";
|
return this.isMultiSelect ? "checkbox" : "radio";
|
||||||
},
|
},
|
||||||
buttonId() {
|
buttonId() {
|
||||||
return `${this.groupName}-${JSON.stringify(this.value)?.replace(
|
return `${this.groupName?.replace(" ", "-")}-${this.value
|
||||||
" ",
|
?.toString()
|
||||||
"-"
|
?.replace(" ", "-")}`;
|
||||||
)}`;
|
},
|
||||||
|
isValueSelectedOnClick() {
|
||||||
|
return this.isMultiSelect || this.selectingInitiatesLoad;
|
||||||
|
},
|
||||||
|
eventTypes() {
|
||||||
|
return {
|
||||||
|
CHANGE: "change",
|
||||||
|
ENTER: "enter",
|
||||||
|
SPACE: "space",
|
||||||
|
CLICK: "click",
|
||||||
|
MOUNT: "mount"
|
||||||
|
};
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
setup(props) {
|
setup(props) {
|
||||||
|
|
|
||||||
|
|
@ -2,189 +2,170 @@ import { shallowMount } from "@vue/test-utils";
|
||||||
import buttonQuestion from "@/common-components/button-question/button-question";
|
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("@/store", () => { return {}; }, { virtual: true });
|
jest.mock(
|
||||||
|
"@/store",
|
||||||
|
() => {
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
{ virtual: true }
|
||||||
|
);
|
||||||
|
|
||||||
// TODO KO
|
describe("buttonQuestion.vue", () => {
|
||||||
describe.skip("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
|
// Assert
|
||||||
// const Div = wrapper.find('fieldset div');
|
const Div = wrapper.find("fieldset div");
|
||||||
// expect(Div.classes()).toContain("row");
|
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
|
// Assert
|
||||||
// const Div = wrapper.find('fieldset div');
|
const Div = wrapper.find("fieldset div");
|
||||||
// expect(Div.classes()).toContain("d-flex");
|
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
|
// Assert
|
||||||
// const Div = wrapper.find('fieldset div');
|
const Div = wrapper.find("fieldset div");
|
||||||
// expect(Div.classes()).toContain("ui-radio");
|
expect(Div.classes()).toContain("ui-radio");
|
||||||
// });
|
});
|
||||||
// });
|
});
|
||||||
|
|
||||||
|
// testing a computed property
|
||||||
|
describe("buttonQuestion.vue", () => {
|
||||||
|
it("getColLength should return '12' if prop isWide is set to true", () => {
|
||||||
|
// Act
|
||||||
|
const localThis = { isWide: true };
|
||||||
|
|
||||||
// // testing a computed property
|
expect(buttonQuestion.computed.getColLength.call(localThis)).toBe("12");
|
||||||
// describe("buttonQuestion.vue", () => {
|
});
|
||||||
// it("getColLength should return '12' if prop isWide is set to true", () => {
|
});
|
||||||
// // Act
|
|
||||||
// const localThis = { isWide: true }
|
|
||||||
|
|
||||||
// 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",
|
||||||
|
};
|
||||||
|
|
||||||
// describe("buttonQuestion.vue", () => {
|
expect(buttonQuestion.computed.getColLength.call(localThis)).toBe("");
|
||||||
// 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" };
|
||||||
|
|
||||||
// describe("buttonQuestion.vue", () => {
|
// Assert
|
||||||
// it("Should return answer.Text if prop useTextForValue is true", async () => {
|
expect(buttonQuestion.methods.getValue.call(localThis, answer)).toBe(
|
||||||
// // Act
|
"testText"
|
||||||
// const localThis = { useTextForValue: true };
|
);
|
||||||
// const answer = { 'Name': 'testName', 'Text': 'testText' };
|
});
|
||||||
|
});
|
||||||
|
|
||||||
// // Assert
|
describe("buttonQuestion.vue", () => {
|
||||||
// expect(buttonQuestion.methods.getValue.call(localThis, answer)).toBe('testText');
|
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" };
|
||||||
|
|
||||||
// describe("buttonQuestion.vue", () => {
|
// Assert
|
||||||
// it("Should return answer.Name if prop useTextForValue is false and answer.Name exists", async () => {
|
expect(buttonQuestion.methods.getValue.call(localThis, answer)).toBe(
|
||||||
// // Act
|
"testName"
|
||||||
// const localThis = { useTextForValue: false };
|
);
|
||||||
// const answer = { 'Name': 'testName', 'Text': 'testText' };
|
});
|
||||||
|
});
|
||||||
|
|
||||||
// // Assert
|
describe("buttonQuestion.vue", () => {
|
||||||
// expect(buttonQuestion.methods.getValue.call(localThis, answer)).toBe('testName');
|
describe("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);
|
||||||
|
|
||||||
// describe("buttonQuestion.vue", () => {
|
// Assert
|
||||||
// it("Should trigger event modelValue change to new value on when radio button selected", async () => {
|
expect(wrapper.emitted()["update:modelValue"][0]).toEqual(["2021"]);
|
||||||
// // Act
|
});
|
||||||
// const wrapper = shallowMount(buttonQuestion, setupMocks({propsData: {groupName: "group-name"}}));
|
|
||||||
// await wrapper.setProps({
|
|
||||||
// answers: ["2022", "2021", "2020"],
|
|
||||||
// isMultiSelect: false,
|
|
||||||
// modelValue: []
|
|
||||||
// });
|
|
||||||
// const val = { checkValue: true, value: "2021", }
|
|
||||||
// wrapper.vm.handleCheckedChanged(val);
|
|
||||||
// // Assert
|
|
||||||
// expect(wrapper.emitted()["update:modelValue"][0]).toEqual([["2021"]]);
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
|
|
||||||
// describe("buttonQuestion.vue", () => {
|
test("is checkbox => should emit captured value", async () => {
|
||||||
// it("Should add values to array on checkbox click", () => {
|
const wrapper = shallowMount(
|
||||||
// // Act
|
buttonQuestion,
|
||||||
// const wrapper = shallowMount(buttonQuestion, setupMocks({
|
setupMocks({ propsData: { groupName: "group-name" } })
|
||||||
// propsData: {
|
);
|
||||||
// modelValue: ["2022", "2021", "2020"],
|
await wrapper.setProps({
|
||||||
// isMultiSelect: true,
|
answers: ["2022", "2021", "2020"],
|
||||||
// groupName: "group-name"
|
isMultiSelect: false,
|
||||||
// }
|
modelValue: "",
|
||||||
// }));
|
});
|
||||||
// const val = { checkValue: true, value: "2019", }
|
const val = ["2022", "2021", , "2019", "2020"];
|
||||||
// wrapper.vm.handleCheckedChanged(val);
|
wrapper.vm.handleAnswerChange(val);
|
||||||
// // Assert
|
|
||||||
// expect(wrapper.emitted()["update:modelValue"][0]).toEqual([["2022", "2021", "2020", "2019"]]);
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
|
|
||||||
// describe("buttonQuestion.vue", () => {
|
// Assert
|
||||||
// it("Should add a value to this.selectedValues if prop isMultiSelect is true, checkValue is true and this.selectedValues already exists", () => {
|
expect(wrapper.emitted()["update:modelValue"][0]).toEqual([
|
||||||
// // Act
|
["2022", "2021", , "2019", "2020"],
|
||||||
// const wrapper = shallowMount(buttonQuestion, setupMocks({
|
]);
|
||||||
// propsData: {
|
});
|
||||||
// isMultiSelect: true,
|
});
|
||||||
// modelValue: ['a', 'b'],
|
});
|
||||||
// groupName: "group-name"
|
|
||||||
// }
|
|
||||||
// }));
|
|
||||||
// const val = { checkValue: true, value: "2021", }
|
|
||||||
// wrapper.vm.handleCheckedChanged(val);
|
|
||||||
|
|
||||||
// // Assert
|
|
||||||
// expect(wrapper.vm.selectedValues).toEqual(["a", "b", "2021"]);
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
|
|
||||||
// describe("buttonQuestion.vue", () => {
|
|
||||||
// it("Should remove a value to this.selectedValues if prop isMultiSelect is true, checkValue is false and this.selectedValues already exists", () => {
|
|
||||||
// // Act
|
|
||||||
// const wrapper = shallowMount(buttonQuestion, setupMocks({
|
|
||||||
// propsData: {
|
|
||||||
// isMultiSelect: true,
|
|
||||||
// modelValue: ['a', 'b'],
|
|
||||||
// groupName: "group-name"
|
|
||||||
// }
|
|
||||||
// }));
|
|
||||||
|
|
||||||
// const val = { checkValue: false, value: "a", }
|
|
||||||
// wrapper.vm.handleCheckedChanged(val);
|
|
||||||
|
|
||||||
// // Assert
|
|
||||||
// expect(wrapper.vm.selectedValues).toEqual(["b"]);
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
|
|
||||||
function setupMocks(mountOptionsMockData = {}) {
|
function setupMocks(mountOptionsMockData = {}) {
|
||||||
const defaultMountOptions = { route: { query: { fmgPage: 'page-name' } } };
|
const defaultMountOptions = { route: { query: { fmgPage: "page-name" } } };
|
||||||
const baseMountOptions = getMountOptions(Object.assign(defaultMountOptions, mountOptionsMockData));
|
const baseMountOptions = getMountOptions(
|
||||||
|
Object.assign(defaultMountOptions, mountOptionsMockData)
|
||||||
|
);
|
||||||
const allMountOptions = Object.assign(defaultMountOptions, baseMountOptions);
|
const allMountOptions = Object.assign(defaultMountOptions, baseMountOptions);
|
||||||
|
|
||||||
return allMountOptions;
|
return allMountOptions;
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,6 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="w-100 d-flex justify-content-center">
|
<div class="w-100 d-flex justify-content-center">
|
||||||
|
|
||||||
<fieldset
|
<fieldset
|
||||||
class="w-100"
|
class="w-100"
|
||||||
:aria-required="isRequired"
|
:aria-required="isRequired"
|
||||||
|
|
@ -52,13 +51,16 @@
|
||||||
:validationRules="validationRules"
|
:validationRules="validationRules"
|
||||||
:textPosition="textPosition"
|
:textPosition="textPosition"
|
||||||
:selectOnKeypress="selectOnKeypress"
|
:selectOnKeypress="selectOnKeypress"
|
||||||
@buttonClicked="handleAnswerChange" />
|
:lastValuePushedToGa="lastValuePushedToGa"
|
||||||
|
:setLastValuePushedToGa="setLastValuePushedToGa"
|
||||||
|
:shouldPushClickEventToGAOnMount="shouldPushClickEventToGAOnMount"
|
||||||
|
@inputButtonClicked="handleAnswerChange" />
|
||||||
<!-- For nested questions -->
|
<!-- For nested questions -->
|
||||||
<transition name="fade" mode="out-in">
|
<transition name="fade" mode="out-in">
|
||||||
<div
|
<div
|
||||||
v-if="
|
v-if="
|
||||||
typeof primaryValue == 'string' &&
|
typeof selectedValues == 'string' &&
|
||||||
primaryValue == answer.value
|
selectedValues == answer.value
|
||||||
">
|
">
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -79,8 +81,8 @@
|
||||||
import listButton from "@/ux-components/list-button/list-button";
|
import listButton from "@/ux-components/list-button/list-button";
|
||||||
import listButtonHorizontal from "@/ux-components/list-button-horizontal/list-button-horizontal";
|
import listButtonHorizontal from "@/ux-components/list-button-horizontal/list-button-horizontal";
|
||||||
import listCard from "@/ux-components/list-card/list-card";
|
import listCard from "@/ux-components/list-card/list-card";
|
||||||
import { ErrorMessage } from "vee-validate";
|
|
||||||
import radio from "@/ux-components/radio/radio";
|
import radio from "@/ux-components/radio/radio";
|
||||||
|
import { ErrorMessage } from "vee-validate";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "buttonQuestion",
|
name: "buttonQuestion",
|
||||||
|
|
@ -120,11 +122,11 @@ export default {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true,
|
default: true,
|
||||||
},
|
},
|
||||||
|
shouldPushClickEventToGAOnMount: Boolean
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
primaryValue: "",
|
lastValuePushedToGa: null,
|
||||||
lastFocusedInputGroup: "",
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
|
@ -196,6 +198,14 @@ export default {
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
selectedValues: {
|
||||||
|
get() {
|
||||||
|
return this.modelValue;
|
||||||
|
},
|
||||||
|
set(selectedAnswers) {
|
||||||
|
this.$emit("update:modelValue", selectedAnswers);
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
formatString(str) {
|
formatString(str) {
|
||||||
|
|
@ -219,10 +229,13 @@ export default {
|
||||||
: this.formatString(answer.toString());
|
: this.formatString(answer.toString());
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
handleAnswerChange(primaryAnswerValue) {
|
handleAnswerChange(selectedAnswers) {
|
||||||
this.primaryValue = primaryAnswerValue;
|
this.selectedValues = selectedAnswers;
|
||||||
this.$emit("buttonQuestionChange", primaryAnswerValue);
|
|
||||||
this.$emit("update:modelValue", primaryAnswerValue);
|
this.$emit("buttonQuestionChange", selectedAnswers);
|
||||||
|
},
|
||||||
|
setLastValuePushedToGa(lastValuePushedToGa) {
|
||||||
|
this.lastValuePushedToGa = lastValuePushedToGa;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@ const storeActions = {
|
||||||
RUN_EXPERIMENTS_FOR_TRIGGER: "runExperimentsForTrigger",
|
RUN_EXPERIMENTS_FOR_TRIGGER: "runExperimentsForTrigger",
|
||||||
CLEAR_VIN: "clearVin",
|
CLEAR_VIN: "clearVin",
|
||||||
RESET_SAVE_SESSION_PROMISE: "resetSaveSessionPromise",
|
RESET_SAVE_SESSION_PROMISE: "resetSaveSessionPromise",
|
||||||
|
|
||||||
// DEPENDENCY MUTATIONS
|
// DEPENDENCY MUTATIONS
|
||||||
RESET_VEHICLE_STATE_AND_DEPENDENCIES: "resetVehicleAndDependencies",
|
RESET_VEHICLE_STATE_AND_DEPENDENCIES: "resetVehicleAndDependencies",
|
||||||
RESET_DAMAGE_STATE_AND_DEPENDENCIES: "resetDamageAndDependencies",
|
RESET_DAMAGE_STATE_AND_DEPENDENCIES: "resetDamageAndDependencies",
|
||||||
|
|
@ -63,12 +64,4 @@ const storeActions = {
|
||||||
SAVE_CAPABILITY_QUESTION_ANSWERS: "saveCapabilityQuestionAnswers",
|
SAVE_CAPABILITY_QUESTION_ANSWERS: "saveCapabilityQuestionAnswers",
|
||||||
};
|
};
|
||||||
|
|
||||||
const gaStoreActions = {
|
export { storeActions };
|
||||||
UPDATE_CURRENTLY_SELECTED_VALUES: "updateCurrentlySelectedValues",
|
|
||||||
UPDATE_FIRED_GA_CLICK_EVENT_VALUES: "updateFiredGaClickEventValues",
|
|
||||||
UPDATE_LAST_FOCUSED_INPUT_GROUP: "updateLastFocusedInputGroup",
|
|
||||||
UPDATE_WAS_LAST_FOCUSED_INPUT_MULTISELECT:
|
|
||||||
"updateWasLastFocusedInputMultiselect",
|
|
||||||
};
|
|
||||||
|
|
||||||
export { storeActions, gaStoreActions };
|
|
||||||
|
|
|
||||||
|
|
@ -68,12 +68,4 @@ const storeMutations = {
|
||||||
UPDATE_TRIGGERED_SITE_ENTRY: "updateTriggeredSiteEntry",
|
UPDATE_TRIGGERED_SITE_ENTRY: "updateTriggeredSiteEntry",
|
||||||
};
|
};
|
||||||
|
|
||||||
const gaStoreMutations = {
|
export { storeMutations };
|
||||||
UPDATE_CURRENTLY_SELECTED_VALUES: "updateCurrentlySelectedValues",
|
|
||||||
UPDATE_FIRED_GA_CLICK_EVENT_VALUES: "updateFiredGaClickEventValues",
|
|
||||||
UPDATE_LAST_FOCUSED_INPUT_GROUP: "updateLastFocusedInputGroup",
|
|
||||||
UPDATE_WAS_LAST_FOCUSED_INPUT_MULTISELECT:
|
|
||||||
"updateWasLastFocusedInputMultiselect",
|
|
||||||
};
|
|
||||||
|
|
||||||
export { storeMutations, gaStoreMutations };
|
|
||||||
|
|
@ -36,8 +36,7 @@ describe("replace-options-question.vue", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("replace-options-question.vue", () => {
|
describe("replace-options-question.vue", () => {
|
||||||
// TODO KO
|
test("when updateSelectedValues method is called with a single answerToDisplay it will call to update this.selectedReplaceOptions", async () => {
|
||||||
test.skip("when updateSelectedValues method is called with a single answerToDisplay it will call to update this.selectedValues", async () => {
|
|
||||||
|
|
||||||
//Arrange
|
//Arrange
|
||||||
const { wrapper, cmsContent, replaceOptions
|
const { wrapper, cmsContent, replaceOptions
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ export default ({
|
||||||
name: "sideDoorOptions",
|
name: "sideDoorOptions",
|
||||||
props: {
|
props: {
|
||||||
groupName: String,
|
groupName: String,
|
||||||
modelValue: Array,
|
modelValue: [Array, Object], // TODO Does this take an array?
|
||||||
selectedDamageLocations: Array,
|
selectedDamageLocations: Array,
|
||||||
cmsWidgetName: String,
|
cmsWidgetName: String,
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -55,8 +55,7 @@ jest.mock("@/store", () => ({
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// TODO KO
|
describe("vehicle-damage.vue", () => {
|
||||||
describe.skip("vehicle-damage.vue", () => {
|
|
||||||
describe("navigation", () => {
|
describe("navigation", () => {
|
||||||
test("BackButtonAction triggers a router.navigateWithoutSaving change", async () => {
|
test("BackButtonAction triggers a router.navigateWithoutSaving change", async () => {
|
||||||
|
|
||||||
|
|
@ -130,20 +129,20 @@ describe.skip("vehicle-damage.vue", () => {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
wrapper.vm.selectedDamageLocations = ["Windshield", "SideDoor", "RearWindow"];
|
wrapper.setData({
|
||||||
wrapper.vm.selectedWindshieldOptions = {
|
selectedDamageLocations: ["Windshield", "SideDoor", "RearWindow"],
|
||||||
selectedWindshieldChipCount: null,
|
selectedWindshieldOptions: {
|
||||||
selectedWindshieldReplaceOptions: ["Single"],
|
selectedWindshieldChipCount: null,
|
||||||
selectedWindshieldDamageType: "Replace"
|
selectedWindshieldReplaceOptions: ["Single"],
|
||||||
};
|
selectedWindshieldDamageType: "Replace"
|
||||||
|
},
|
||||||
wrapper.vm.sideDoorOptionsData = {
|
sideDoorOptionsData: {
|
||||||
selectedDoorSides: ["DriverSide", "PassengerSide"],
|
selectedDoorSides: ["DriverSide", "PassengerSide"],
|
||||||
selectedDriverSideReplaceOptions: ["Back"],
|
selectedDriverSideReplaceOptions: ["Back"],
|
||||||
selectedPassengerSideReplaceOptions: ["Quarter"]
|
selectedPassengerSideReplaceOptions: ["Quarter"]
|
||||||
};
|
},
|
||||||
|
selectedRearReplaceOptions: "Stationary",
|
||||||
wrapper.vm.selectedRearReplaceOptions = ["Stationary"];
|
})
|
||||||
|
|
||||||
const expectedGlassToReplace = [{ glassLocation: "Windshield", glassName: "Single" }, { glassLocation: "Driver", glassName: "Back" },
|
const expectedGlassToReplace = [{ glassLocation: "Windshield", glassName: "Single" }, { glassLocation: "Driver", glassName: "Back" },
|
||||||
{ glassLocation: "Passenger", glassName: "Quarter" }, { glassLocation: "Rear", glassName: "Stationary" }];
|
{ glassLocation: "Passenger", glassName: "Quarter" }, { glassLocation: "Rear", glassName: "Stationary" }];
|
||||||
|
|
@ -520,19 +519,19 @@ describe.skip("vehicle-damage.vue", () => {
|
||||||
|
|
||||||
const storeWindshieldOptions = [[1, false, "Windshield", "Single", {
|
const storeWindshieldOptions = [[1, false, "Windshield", "Single", {
|
||||||
selectedWindshieldDamageType: damageLocationsSelected.REPLACE,
|
selectedWindshieldDamageType: damageLocationsSelected.REPLACE,
|
||||||
selectedWindshieldChipCount: [], selectedWindshieldReplaceOptions: [damageLocationsSelected.SINGLE]
|
selectedWindshieldChipCount: null, selectedWindshieldReplaceOptions: [damageLocationsSelected.SINGLE]
|
||||||
}],
|
}],
|
||||||
[2, false, "Windshield", "Driver", {
|
[2, false, "Windshield", "Driver", {
|
||||||
selectedWindshieldDamageType: damageLocationsSelected.REPLACE,
|
selectedWindshieldDamageType: damageLocationsSelected.REPLACE,
|
||||||
selectedWindshieldChipCount: [], selectedWindshieldReplaceOptions: [damageLocationsSelected.DRIVER]
|
selectedWindshieldChipCount: null, selectedWindshieldReplaceOptions: [damageLocationsSelected.DRIVER]
|
||||||
}],
|
}],
|
||||||
[3, false, "Windshield", "Passenger", {
|
[3, false, "Windshield", "Passenger", {
|
||||||
selectedWindshieldDamageType: damageLocationsSelected.REPLACE,
|
selectedWindshieldDamageType: damageLocationsSelected.REPLACE,
|
||||||
selectedWindshieldChipCount: [], selectedWindshieldReplaceOptions: [damageLocationsSelected.PASSENGER]
|
selectedWindshieldChipCount: null, selectedWindshieldReplaceOptions: [damageLocationsSelected.PASSENGER]
|
||||||
}],
|
}],
|
||||||
[4, true, "", "", {
|
[4, true, "", "", {
|
||||||
selectedWindshieldDamageType: damageLocationsSelected.REPAIR,
|
selectedWindshieldDamageType: damageLocationsSelected.REPAIR,
|
||||||
selectedWindshieldChipCount: [2], selectedWindshieldReplaceOptions: []
|
selectedWindshieldChipCount: 2, selectedWindshieldReplaceOptions: []
|
||||||
}]
|
}]
|
||||||
];
|
];
|
||||||
test.each(storeWindshieldOptions)("getWindshieldOptionsFromStore test #%s", async (testNum, isRepair, damageLocation, damageName, expectedWindshieldOptions) => {
|
test.each(storeWindshieldOptions)("getWindshieldOptionsFromStore test #%s", async (testNum, isRepair, damageLocation, damageName, expectedWindshieldOptions) => {
|
||||||
|
|
@ -619,8 +618,8 @@ describe.skip("vehicle-damage.vue", () => {
|
||||||
expect(glassSelections).toEqual(expectedGlass);
|
expect(glassSelections).toEqual(expectedGlass);
|
||||||
});
|
});
|
||||||
|
|
||||||
const rearReplaceOptions = [["Rear", "Stationary", [damageLocationsSelected.STATIONARY]],
|
const rearReplaceOptions = [["Rear", "Stationary", damageLocationsSelected.STATIONARY],
|
||||||
["Rear", "Slider", [damageLocationsSelected.SLIDER]]
|
["Rear", "Slider", damageLocationsSelected.SLIDER]
|
||||||
];
|
];
|
||||||
test.each(rearReplaceOptions)("getRearReplaceOptionsFromStore for %s-%s returns expected %s", async (damageLocation, damageName, expectedGlass) => {
|
test.each(rearReplaceOptions)("getRearReplaceOptionsFromStore for %s-%s returns expected %s", async (damageLocation, damageName, expectedGlass) => {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,7 @@ export default ({
|
||||||
},
|
},
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
modelValue: String,
|
modelValue: [Object, String], // TODO Does this take a string?
|
||||||
selectedDamageLocations: Array,
|
selectedDamageLocations: Array,
|
||||||
hasRepairReplaceConflict: Boolean,
|
hasRepairReplaceConflict: Boolean,
|
||||||
hasSplitSingleConflict: Boolean,
|
hasSplitSingleConflict: Boolean,
|
||||||
|
|
|
||||||
|
|
@ -18,9 +18,7 @@ const featureListData = {
|
||||||
modelValueProp: {}
|
modelValueProp: {}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO KO
|
describe("glass-part-question.vue", () => {
|
||||||
describe.skip("glass-part-question.vue", () => {
|
|
||||||
|
|
||||||
test("Part data passed in, should map data for ButtonQuestion (radio type)", async () => {
|
test("Part data passed in, should map data for ButtonQuestion (radio type)", async () => {
|
||||||
|
|
||||||
//Arrange
|
//Arrange
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,7 @@
|
||||||
altText=""
|
altText=""
|
||||||
isRequired
|
isRequired
|
||||||
:groupName="`${glassLocation}-${glassName}`"
|
:groupName="`${glassLocation}-${glassName}`"
|
||||||
:validationRules="tintValidationRules"
|
:validationRules="tintValidationRules">
|
||||||
>
|
|
||||||
<div class="row my-2" aria-live="polite">
|
<div class="row my-2" aria-live="polite">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<buttonQuestion
|
<buttonQuestion
|
||||||
|
|
@ -28,7 +27,9 @@
|
||||||
isRequired
|
isRequired
|
||||||
:groupName="`${glassLocation}-${glassName}-${selectedTint}`"
|
:groupName="`${glassLocation}-${glassName}-${selectedTint}`"
|
||||||
:validationRules="partValidationRules"
|
:validationRules="partValidationRules"
|
||||||
/>
|
:shouldPushClickEventToGAOnMount="
|
||||||
|
shouldPushClickEventToGAOnMount
|
||||||
|
" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</buttonQuestion>
|
</buttonQuestion>
|
||||||
|
|
@ -56,6 +57,7 @@ export default {
|
||||||
glassColorQuestion: "",
|
glassColorQuestion: "",
|
||||||
glassFeatureQuestion: "",
|
glassFeatureQuestion: "",
|
||||||
selectedTint: "",
|
selectedTint: "",
|
||||||
|
shouldPushClickEventToGAOnMount: true,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
|
|
@ -63,7 +65,10 @@ export default {
|
||||||
glassLocation: String,
|
glassLocation: String,
|
||||||
colorAnswers: Array,
|
colorAnswers: Array,
|
||||||
modelValue: Object,
|
modelValue: Object,
|
||||||
alreadyPopulatedPartsData: Array
|
alreadyPopulatedPartsData: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.LoadPreselectedValues();
|
this.LoadPreselectedValues();
|
||||||
|
|
@ -74,12 +79,18 @@ export default {
|
||||||
computed: {
|
computed: {
|
||||||
tintValidationRules() {
|
tintValidationRules() {
|
||||||
const validationRuleName = `${this.glassLocation}-${this.glassName}-tint-required`;
|
const validationRuleName = `${this.glassLocation}-${this.glassName}-tint-required`;
|
||||||
defineRule(validationRuleName, required(errorMessages.OPTION_REQUIRED));
|
defineRule(
|
||||||
|
validationRuleName,
|
||||||
|
required(errorMessages.OPTION_REQUIRED)
|
||||||
|
);
|
||||||
return validationRuleName;
|
return validationRuleName;
|
||||||
},
|
},
|
||||||
partValidationRules() {
|
partValidationRules() {
|
||||||
const validationRuleName = `${this.glassLocation}-${this.glassName}-part-required`;
|
const validationRuleName = `${this.glassLocation}-${this.glassName}-part-required`;
|
||||||
defineRule(validationRuleName, required(errorMessages.OPTION_REQUIRED));
|
defineRule(
|
||||||
|
validationRuleName,
|
||||||
|
required(errorMessages.OPTION_REQUIRED)
|
||||||
|
);
|
||||||
return validationRuleName;
|
return validationRuleName;
|
||||||
},
|
},
|
||||||
colorQuestionText() {
|
colorQuestionText() {
|
||||||
|
|
@ -110,16 +121,29 @@ export default {
|
||||||
return this.modelValue?.partNumber;
|
return this.modelValue?.partNumber;
|
||||||
},
|
},
|
||||||
set(newValue) {
|
set(newValue) {
|
||||||
this.$emit("update:modelValue", this.partsForSelectedTint.filter(part => part.partNumber == newValue)[0]);
|
this.$emit(
|
||||||
|
"update:modelValue",
|
||||||
|
this.partsForSelectedTint.filter(
|
||||||
|
(part) => part.partNumber == newValue
|
||||||
|
)[0]
|
||||||
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
partsForSelectedTint() {
|
partsForSelectedTint() {
|
||||||
const matchingGlass = this.PartDataFromApi.partsOrQuestions?.filter(dataForGlassLocationAndName =>
|
const matchingGlass = this.PartDataFromApi.partsOrQuestions?.filter(
|
||||||
dataForGlassLocationAndName.glassName == this.glassName &&
|
(dataForGlassLocationAndName) =>
|
||||||
dataForGlassLocationAndName.glassLocation == this.glassLocation);
|
dataForGlassLocationAndName.glassName == this.glassName &&
|
||||||
const matchingGlassParts = matchingGlass?.length == 1 ? matchingGlass[0].parts : [];
|
dataForGlassLocationAndName.glassLocation ==
|
||||||
return matchingGlassParts.filter(part => part.color == this.selectedTint) ?? [];
|
this.glassLocation
|
||||||
|
);
|
||||||
|
const matchingGlassParts =
|
||||||
|
matchingGlass?.length == 1 ? matchingGlass[0].parts : [];
|
||||||
|
return (
|
||||||
|
matchingGlassParts.filter(
|
||||||
|
(part) => part.color == this.selectedTint
|
||||||
|
) ?? []
|
||||||
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
// Creates a map of the feature list data in the correct Name/Value
|
// Creates a map of the feature list data in the correct Name/Value
|
||||||
|
|
@ -151,7 +175,9 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
PartDataFromApi() {
|
PartDataFromApi() {
|
||||||
return this.$store.getters.pageData(this.$route.query.fmgPage) ?? {};
|
return (
|
||||||
|
this.$store.getters.pageData(this.$route.query.fmgPage) ?? {}
|
||||||
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
@ -188,7 +214,8 @@ export default {
|
||||||
// Check if only a single part is present for the tint and set the v-model if it is.
|
// Check if only a single part is present for the tint and set the v-model if it is.
|
||||||
AutoSelectIfSinglePart() {
|
AutoSelectIfSinglePart() {
|
||||||
if (this.partsForSelectedTint?.length == 1) {
|
if (this.partsForSelectedTint?.length == 1) {
|
||||||
this.selectedPartNumber = this.partsForSelectedTint[0].partNumber;
|
this.selectedPartNumber =
|
||||||
|
this.partsForSelectedTint[0].partNumber;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -197,7 +224,8 @@ export default {
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
if (this.modelValue !== undefined) {
|
if (this.modelValue !== undefined) {
|
||||||
// Populate button-question model-value if parts data already exists in VueX
|
// Populate button-question model-value if parts data already exists in VueX
|
||||||
this.selectedTint = this.alreadyPopulatedPartsData.filter(part => part.partNumber === this.selectedPartNumber)[0]?.color;
|
this.shouldPushClickEventToGAOnMount = false;
|
||||||
|
this.selectedTint = this.modelValue?.color
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
@ -205,8 +233,8 @@ export default {
|
||||||
watch: {
|
watch: {
|
||||||
selectedTint() {
|
selectedTint() {
|
||||||
this.AutoSelectIfSinglePart();
|
this.AutoSelectIfSinglePart();
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -183,7 +183,16 @@ describe("vehicle-parts.vue", () => {
|
||||||
await nextTick();
|
await nextTick();
|
||||||
|
|
||||||
//Assert
|
//Assert
|
||||||
expect(wrapper.vm.glassParts).toEqual({ "Rear-Stationary": { "Rear": ['DB12209YPYNOEM'] } });
|
expect(wrapper.vm.glassParts).toEqual({
|
||||||
|
"Rear-Stationary": {
|
||||||
|
partNumber: "DB12209YPYNOEM",
|
||||||
|
description: "heated glass, solar, 1 hole",
|
||||||
|
color: "Gray Tint Privacy",
|
||||||
|
requiresRecalibration: false,
|
||||||
|
requiresCapabilityQuestions: false,
|
||||||
|
childParts: null
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test("User had part questions > BackButtonAction triggers a router.navigateWithoutSaving change with correct scenario", async () => {
|
test("User had part questions > BackButtonAction triggers a router.navigateWithoutSaving change with correct scenario", async () => {
|
||||||
|
|
@ -509,6 +518,8 @@ function setupMocks({ pageHeaderWidgetHeaderText = {}, mountOptionsMockData = {}
|
||||||
wrapper.vm.setCmsContent = baseMixin.methods.setCmsContent;
|
wrapper.vm.setCmsContent = baseMixin.methods.setCmsContent;
|
||||||
wrapper.vm.$refs.funnelFooter.removeLoader = jest.fn();
|
wrapper.vm.$refs.funnelFooter.removeLoader = jest.fn();
|
||||||
wrapper.vm.$refs.loadingModal.showModal = jest.fn();
|
wrapper.vm.$refs.loadingModal.showModal = jest.fn();
|
||||||
|
// wrapper.vm.$refs.onSubmit = jest.fn();
|
||||||
|
// wrapper.vm.$refs.onInvalidSubmit = jest.fn();
|
||||||
|
|
||||||
return { wrapper, apiPromise };
|
return { wrapper, apiPromise };
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -204,9 +204,7 @@ export default {
|
||||||
const partNumber = this.alreadyPopulatedPartsData[key].partNumber;
|
const partNumber = this.alreadyPopulatedPartsData[key].partNumber;
|
||||||
g.parts.forEach((p) => {
|
g.parts.forEach((p) => {
|
||||||
if (p.partNumber === partNumber) {
|
if (p.partNumber === partNumber) {
|
||||||
this.glassParts[g.glassLocation + "-" + g.glassName] = {
|
this.glassParts[g.glassLocation + "-" + g.glassName] = p;
|
||||||
[g.glassLocation]: [partNumber],
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -6,12 +6,11 @@ import { vehicleCategories } from "@/constants/vehicle-categories.js";
|
||||||
import { routerParams } from "@/router/router-constants/router-params";
|
import { routerParams } from "@/router/router-constants/router-params";
|
||||||
import { queryStrings } from "@/constants/query-strings";
|
import { queryStrings } from "@/constants/query-strings";
|
||||||
import { dynamicStrings } from "@/constants/dynamic-strings";
|
import { dynamicStrings } from "@/constants/dynamic-strings";
|
||||||
import { settleAllPromises } from "@/helpers/layout-helper";
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
cmsContentByWidget: {}
|
cmsContentByWidget: {},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
@ -19,7 +18,9 @@ export default {
|
||||||
this.$root.cmsContentByWidget = cmsContent;
|
this.$root.cmsContentByWidget = cmsContent;
|
||||||
},
|
},
|
||||||
getCmsContent(widgetName, fieldName) {
|
getCmsContent(widgetName, fieldName) {
|
||||||
return this.$root.cmsContentByWidget?.[widgetName]?.[fieldName] ? this.$root.cmsContentByWidget[widgetName][fieldName] : '';
|
return this.$root.cmsContentByWidget?.[widgetName]?.[fieldName]
|
||||||
|
? this.$root.cmsContentByWidget[widgetName][fieldName]
|
||||||
|
: "";
|
||||||
},
|
},
|
||||||
dispatchStoreAction(type, payload, encodePayload = true) {
|
dispatchStoreAction(type, payload, encodePayload = true) {
|
||||||
// Encode the payload if required
|
// Encode the payload if required
|
||||||
|
|
@ -32,7 +33,7 @@ export default {
|
||||||
savePageDataToStore(page, data) {
|
savePageDataToStore(page, data) {
|
||||||
store.commit(storeMutations.UPDATE_PAGE_DATA, { page: page, data: data });
|
store.commit(storeMutations.UPDATE_PAGE_DATA, { page: page, data: data });
|
||||||
},
|
},
|
||||||
onSubmit() { }, // DO NOT REMOVE; needed to prevent default form submit behavior. Cannot use .prevent modifier for vee-validate Form
|
onSubmit() {}, // DO NOT REMOVE; needed to prevent default form submit behavior. Cannot use .prevent modifier for vee-validate Form
|
||||||
onInvalidSubmit({ values, errors, results }) {
|
onInvalidSubmit({ values, errors, results }) {
|
||||||
// identify the first error field and put focus on it
|
// identify the first error field and put focus on it
|
||||||
// get error names array
|
// get error names array
|
||||||
|
|
@ -49,14 +50,17 @@ export default {
|
||||||
return footerInfoBox ? footerInfoBox.offsetHeight : 0;
|
return footerInfoBox ? footerInfoBox.offsetHeight : 0;
|
||||||
},
|
},
|
||||||
async getZipCodeData(zipCode) {
|
async getZipCodeData(zipCode) {
|
||||||
const serviceZipValidationResponse = await this.dispatchStoreAction(storeActions.VALIDATE_ZIP, { zip: zipCode });
|
const serviceZipValidationResponse = await this.dispatchStoreAction(
|
||||||
|
storeActions.VALIDATE_ZIP,
|
||||||
|
{ zip: zipCode }
|
||||||
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
isValid: serviceZipValidationResponse.data.isValid,
|
isValid: serviceZipValidationResponse.data.isValid,
|
||||||
isServiceable: serviceZipValidationResponse.data.isServiceable,
|
isServiceable: serviceZipValidationResponse.data.isServiceable,
|
||||||
state: serviceZipValidationResponse.data.state
|
state: serviceZipValidationResponse.data.state,
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
storeActions() {
|
storeActions() {
|
||||||
|
|
@ -74,13 +78,13 @@ export default {
|
||||||
routerParams() {
|
routerParams() {
|
||||||
return routerParams;
|
return routerParams;
|
||||||
},
|
},
|
||||||
queryStrings(){
|
queryStrings() {
|
||||||
return queryStrings;
|
return queryStrings;
|
||||||
},
|
},
|
||||||
dynamicStrings(){
|
dynamicStrings() {
|
||||||
return dynamicStrings;
|
return dynamicStrings;
|
||||||
},
|
},
|
||||||
cssClassNameForCmsWidget(){
|
cssClassNameForCmsWidget() {
|
||||||
return "widget-name-" + this.cmsWidgetName;
|
return "widget-name-" + this.cmsWidgetName;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ export default {
|
||||||
buttonImage: String,
|
buttonImage: String,
|
||||||
altText: {
|
altText: {
|
||||||
type: String,
|
type: String,
|
||||||
default: ""
|
default: "",
|
||||||
},
|
},
|
||||||
textPosition: String,
|
textPosition: String,
|
||||||
screenReaderOnlyText: String,
|
screenReaderOnlyText: String,
|
||||||
|
|
@ -18,29 +18,19 @@ export default {
|
||||||
isWide: Boolean,
|
isWide: Boolean,
|
||||||
isRequired: {
|
isRequired: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true
|
default: true,
|
||||||
}
|
},
|
||||||
},
|
lastValuePushedToGa: [String, Number],
|
||||||
data() {
|
setLastValuePushedToGa: Function,
|
||||||
return {
|
shouldPushClickEventToGAOnMount: Boolean
|
||||||
selectedValue: null,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
this.selectedValue = this.modelValue;
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
handleAnswerChange(e) {
|
handleAnswerChange(e) {
|
||||||
if (this.preHandleAnswerChange) {
|
if (this.preHandleAnswerChange) {
|
||||||
this.preHandleAnswerChange(e)
|
this.preHandleAnswerChange(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.$emit("change", e);
|
this.$emit("change", e);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
watch: {
|
|
||||||
selectedValue(selectedValue) {
|
|
||||||
this.$emit("update:modelValue", selectedValue);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
|
||||||
81
src/mixins/input-button-wrapper-mixin.spec.js
Normal file
81
src/mixins/input-button-wrapper-mixin.spec.js
Normal file
|
|
@ -0,0 +1,81 @@
|
||||||
|
describe("input-button-wrapper-mixin", () => {
|
||||||
|
describe("mouse clicks", () => {
|
||||||
|
describe("checkbox", () => {
|
||||||
|
test.todo("clicking once checks the baseInputButton");
|
||||||
|
|
||||||
|
test.todo("clicking twice unchecks the baseInputButton");
|
||||||
|
|
||||||
|
test.todo(
|
||||||
|
"is initially checked => checking unchecks the baseInputButton"
|
||||||
|
);
|
||||||
|
|
||||||
|
test.todo("clicked => correct event and value are emitted");
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("radio", () => {
|
||||||
|
test.todo("clicking once selects the baseInputButton");
|
||||||
|
|
||||||
|
test.todo("clicking twice keeps the baseInputButton selected");
|
||||||
|
|
||||||
|
test.todo(
|
||||||
|
"is initially selected => click keeps the baseInputButton selected"
|
||||||
|
);
|
||||||
|
|
||||||
|
test.todo("clicked => correct event and value are emitted");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("keyboard navigation and", () => {
|
||||||
|
describe("checkbox", () => {
|
||||||
|
test.todo(
|
||||||
|
"focus on a checkbox => inputButtonClicked is not emitted"
|
||||||
|
);
|
||||||
|
|
||||||
|
test.todo(
|
||||||
|
"blur from a checkbox => inputButtonClicked is not emitted"
|
||||||
|
);
|
||||||
|
|
||||||
|
test.todo(
|
||||||
|
"focus and click space on a checkbox => inputButtonClicked is emitted with correct value"
|
||||||
|
);
|
||||||
|
|
||||||
|
test.todo(
|
||||||
|
"focus and click space on a checkbox that is already checked => inputButtonClicked is emitted with correct value"
|
||||||
|
);
|
||||||
|
|
||||||
|
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", () => {
|
||||||
|
test.todo(
|
||||||
|
"focus on a radio button => inputButtonClicked is not emitted"
|
||||||
|
);
|
||||||
|
|
||||||
|
test.todo(
|
||||||
|
"blur from a radio button => inputButtonClicked is not emitted"
|
||||||
|
);
|
||||||
|
|
||||||
|
test.todo(
|
||||||
|
"focus and click space on a radio button => inputButtonClicked is emitted with correct value"
|
||||||
|
);
|
||||||
|
|
||||||
|
test.todo(
|
||||||
|
"focus and click space on a radio button that is already selected => inputButtonClicked is emitted with correct value"
|
||||||
|
);
|
||||||
|
|
||||||
|
test.todo(
|
||||||
|
"focus and click enter on a radio button => inputButtonClicked is emitted with correct value"
|
||||||
|
);
|
||||||
|
|
||||||
|
test.todo(
|
||||||
|
"focus and click enter on a radio button that is already selected => inputButtonClicked is emitted with correct value"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -1,90 +0,0 @@
|
||||||
import { createStore } from "vuex";
|
|
||||||
import { endpoints } from "@/constants/endpoints.js";
|
|
||||||
import { gaStoreMutations } from "@/constants/store-mutations";
|
|
||||||
import { getDateForSavedSessionTimeout } from "@/helpers/heritage-integration/session-helper";
|
|
||||||
import createPersistedState from "vuex-persistedstate";
|
|
||||||
import globalMethods from "@/global-methods";
|
|
||||||
import { gaStoreActions } from "@/constants/store-actions";
|
|
||||||
import { applicationConfig } from "@/constants/application-config";
|
|
||||||
import { experimentTriggers } from "@/constants/experiments";
|
|
||||||
import { damageLocationsSelected } from "@/constants/damage-locations-selected";
|
|
||||||
import { fmgPageValues } from "@/router/router-constants/fmgPage-values";
|
|
||||||
|
|
||||||
// Export State
|
|
||||||
const getDefaultState = () => {
|
|
||||||
return {
|
|
||||||
gaClickInformation: {
|
|
||||||
currentlySelectedValues: {},
|
|
||||||
firedGaClickEventValues: {},
|
|
||||||
lastFocusedInputGroup: "",
|
|
||||||
wasLastFocusedInputMultiselect: undefined,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export const gaState = getDefaultState();
|
|
||||||
|
|
||||||
// Export Mutations
|
|
||||||
export const gaMutations = {
|
|
||||||
updateCurrentlySelectedValues(state, groupName, value) {
|
|
||||||
state.gaClickInformation.currentlySelectedValues[groupName] = value;
|
|
||||||
},
|
|
||||||
updateFiredGaClickEventValues(state, groupName, value) {
|
|
||||||
state.gaClickInformation.firedGaClickEventValues[groupName] = value;
|
|
||||||
},
|
|
||||||
updateLastFocusedInputGroup(state, groupName) {
|
|
||||||
state.gaClickInformation.lastFocusedInputGroup = groupName;
|
|
||||||
},
|
|
||||||
updateWasLastFocusedInputMultiselect(
|
|
||||||
state,
|
|
||||||
wasLastFocusedInputMultiselect
|
|
||||||
) {
|
|
||||||
state.gaClickInformation.wasLastFocusedInputMultiselect =
|
|
||||||
wasLastFocusedInputMultiselect;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
// Export Getters
|
|
||||||
export const getters = {
|
|
||||||
gaClickInformation: (state) => state.gaClickInformation,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Export Actions
|
|
||||||
export const gaActions = {
|
|
||||||
updateCurrentlySelectedValues(context, groupName, value) {
|
|
||||||
context.commit(
|
|
||||||
gaStoreMutations.UPDATE_CURRENTLY_SELECTED_VALUES,
|
|
||||||
groupName,
|
|
||||||
value
|
|
||||||
);
|
|
||||||
},
|
|
||||||
updateFiredGaClickEventValues(context, groupName, value) {
|
|
||||||
context.commit(
|
|
||||||
gaStoreMutations.UPDATE_FIRED_GA_CLICK_EVENT_VALUES,
|
|
||||||
groupName,
|
|
||||||
value
|
|
||||||
);
|
|
||||||
},
|
|
||||||
updateLastFocusedInputGroup(context, groupName) {
|
|
||||||
context.commit(
|
|
||||||
gaStoreMutations.UPDATE_LAST_FOCUSED_INPUT_GROUP,
|
|
||||||
groupName
|
|
||||||
);
|
|
||||||
},
|
|
||||||
updateWasLastFocusedInputMultiselect(
|
|
||||||
context,
|
|
||||||
wasLastFocusedInputMultiselect
|
|
||||||
) {
|
|
||||||
context.commit(
|
|
||||||
gaStoreMutations.UPDATE_WAS_LAST_FOCUSED_INPUT_MULTISELECT,
|
|
||||||
wasLastFocusedInputMultiselect
|
|
||||||
);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default createStore({
|
|
||||||
gaState,
|
|
||||||
gaMutations,
|
|
||||||
getters,
|
|
||||||
gaActions,
|
|
||||||
});
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { createStore } from "vuex";
|
import { createStore, Store } from "vuex";
|
||||||
import { endpoints } from "@/constants/endpoints.js";
|
import { endpoints } from "@/constants/endpoints.js";
|
||||||
import { storeMutations } from "@/constants/store-mutations";
|
import { storeMutations } from "@/constants/store-mutations";
|
||||||
import { getDateForSavedSessionTimeout } from "@/helpers/heritage-integration/session-helper";
|
import { getDateForSavedSessionTimeout } from "@/helpers/heritage-integration/session-helper";
|
||||||
|
|
@ -50,22 +50,22 @@ const getDefaultState = () => {
|
||||||
glassToReplace: null,
|
glassToReplace: null,
|
||||||
partQuestionAnswers: null,
|
partQuestionAnswers: null,
|
||||||
moldingQuestionAnswers: null,
|
moldingQuestionAnswers: null,
|
||||||
capabilityQuestionAnswers: null
|
capabilityQuestionAnswers: null,
|
||||||
},
|
},
|
||||||
lineItems: {
|
lineItems: {
|
||||||
glassParts: null
|
glassParts: null,
|
||||||
},
|
},
|
||||||
payment: {
|
payment: {
|
||||||
isInsurance: null,
|
isInsurance: null,
|
||||||
insuranceCoverage: {
|
insuranceCoverage: {
|
||||||
isVerified: null
|
isVerified: null,
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
referralNumber: null,
|
referralNumber: null,
|
||||||
referralDate: null,
|
referralDate: null,
|
||||||
referralCorrelationId: null,
|
referralCorrelationId: null,
|
||||||
accountNumber: 0,
|
accountNumber: 0,
|
||||||
eon: null
|
eon: null,
|
||||||
},
|
},
|
||||||
applicationUser: {
|
applicationUser: {
|
||||||
eventBus: [],
|
eventBus: [],
|
||||||
|
|
@ -76,14 +76,15 @@ const getDefaultState = () => {
|
||||||
crmCustomerId: null,
|
crmCustomerId: null,
|
||||||
lastPageVisited: null,
|
lastPageVisited: null,
|
||||||
experiments: [],
|
experiments: [],
|
||||||
triggeredSiteEntry: false
|
triggeredSiteEntry: false,
|
||||||
},
|
},
|
||||||
gaInformation: {
|
// gaClickInformation: {
|
||||||
currentlySelectedValues: {},
|
// currentlySelectedValues: {},
|
||||||
firedGaClickEventValues: {},
|
// firedGaClickEventValues: {},
|
||||||
lastFocusedInputGroup: ""
|
// lastFocusedInputGroup: "",
|
||||||
}
|
// wasLastFocusedInputMultiselect: undefined,
|
||||||
}
|
// },
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const state = getDefaultState();
|
export const state = getDefaultState();
|
||||||
|
|
@ -200,7 +201,6 @@ export const mutations = {
|
||||||
state.order.customer.emailAddress = customerEmailAddress;
|
state.order.customer.emailAddress = customerEmailAddress;
|
||||||
},
|
},
|
||||||
updateVehicle(state, vehicleInfo) {
|
updateVehicle(state, vehicleInfo) {
|
||||||
|
|
||||||
state.order.vehicle.year = vehicleInfo.year;
|
state.order.vehicle.year = vehicleInfo.year;
|
||||||
state.order.vehicle.make = vehicleInfo.make;
|
state.order.vehicle.make = vehicleInfo.make;
|
||||||
state.order.vehicle.model = vehicleInfo.model;
|
state.order.vehicle.model = vehicleInfo.model;
|
||||||
|
|
@ -214,7 +214,8 @@ export const mutations = {
|
||||||
state.order.vehicle.imageColor = vehicleInfo.imageVifColor;
|
state.order.vehicle.imageColor = vehicleInfo.imageVifColor;
|
||||||
},
|
},
|
||||||
updateRegistration(state, registrationInfo) {
|
updateRegistration(state, registrationInfo) {
|
||||||
state.order.vehicle.registration.licensePlate = registrationInfo?.licensePlate;
|
state.order.vehicle.registration.licensePlate =
|
||||||
|
registrationInfo?.licensePlate;
|
||||||
state.order.vehicle.registration.address = registrationInfo?.address;
|
state.order.vehicle.registration.address = registrationInfo?.address;
|
||||||
state.order.vehicle.registration.city = registrationInfo?.city;
|
state.order.vehicle.registration.city = registrationInfo?.city;
|
||||||
state.order.vehicle.registration.state = registrationInfo?.state;
|
state.order.vehicle.registration.state = registrationInfo?.state;
|
||||||
|
|
@ -240,7 +241,7 @@ export const mutations = {
|
||||||
state.applicationUser.crmCustomerId = crmCustomerId;
|
state.applicationUser.crmCustomerId = crmCustomerId;
|
||||||
},
|
},
|
||||||
updateLastPageVisited(state, lastPageVisited) {
|
updateLastPageVisited(state, lastPageVisited) {
|
||||||
state.applicationUser.lastPageVisited = lastPageVisited
|
state.applicationUser.lastPageVisited = lastPageVisited;
|
||||||
},
|
},
|
||||||
// EVENT BUS MUTATIONS
|
// EVENT BUS MUTATIONS
|
||||||
addEventToBus(state, event) {
|
addEventToBus(state, event) {
|
||||||
|
|
@ -249,8 +250,7 @@ export const mutations = {
|
||||||
removeEventFromBus(state, eventData) {
|
removeEventFromBus(state, eventData) {
|
||||||
const matchedEvent = state.applicationUser.eventBus.find(
|
const matchedEvent = state.applicationUser.eventBus.find(
|
||||||
({ category, subCategory }) =>
|
({ category, subCategory }) =>
|
||||||
category === eventData.category &&
|
category === eventData.category && subCategory === eventData.subCategory
|
||||||
subCategory === eventData.subCategory
|
|
||||||
);
|
);
|
||||||
const itemIndex = state.applicationUser.eventBus.indexOf(matchedEvent);
|
const itemIndex = state.applicationUser.eventBus.indexOf(matchedEvent);
|
||||||
|
|
||||||
|
|
@ -336,7 +336,7 @@ export const mutations = {
|
||||||
state: orderInformation.vehicle.registration.state,
|
state: orderInformation.vehicle.registration.state,
|
||||||
zipCode: orderInformation.vehicle.registration.zipCode,
|
zipCode: orderInformation.vehicle.registration.zipCode,
|
||||||
licensePlate: orderInformation.vehicle.registration.licensePlateNumber,
|
licensePlate: orderInformation.vehicle.registration.licensePlateNumber,
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
state.order.damage.glassToReplace = orderInformation.damage.glassToReplace;
|
state.order.damage.glassToReplace = orderInformation.damage.glassToReplace;
|
||||||
|
|
@ -345,13 +345,18 @@ export const mutations = {
|
||||||
|
|
||||||
state.order.lineItems.glassParts = orderInformation.parts;
|
state.order.lineItems.glassParts = orderInformation.parts;
|
||||||
state.order.accountNumber = orderInformation.accountNumber;
|
state.order.accountNumber = orderInformation.accountNumber;
|
||||||
state.order.serviceLocation.address = orderInformation.serviceLocation.streetAddress,
|
(state.order.serviceLocation.address =
|
||||||
state.order.serviceLocation.city = orderInformation.serviceLocation.city,
|
orderInformation.serviceLocation.streetAddress),
|
||||||
state.order.serviceLocation.state = orderInformation.serviceLocation.state,
|
(state.order.serviceLocation.city =
|
||||||
state.order.serviceLocation.zipCode = orderInformation.serviceLocation.zipCode;
|
orderInformation.serviceLocation.city),
|
||||||
|
(state.order.serviceLocation.state =
|
||||||
|
orderInformation.serviceLocation.state),
|
||||||
|
(state.order.serviceLocation.zipCode =
|
||||||
|
orderInformation.serviceLocation.zipCode);
|
||||||
|
|
||||||
state.order.payment.isInsurance = orderInformation.IsInsuranceOrder;
|
state.order.payment.isInsurance = orderInformation.IsInsuranceOrder;
|
||||||
state.order.payment.insuranceCoverage.isVerified = orderInformation?.insuranceInfo.coverageVerified;
|
state.order.payment.insuranceCoverage.isVerified =
|
||||||
|
orderInformation?.insuranceInfo.coverageVerified;
|
||||||
|
|
||||||
state.order.customer.emailAddress = orderInformation.customer.emailAddress;
|
state.order.customer.emailAddress = orderInformation.customer.emailAddress;
|
||||||
state.applicationUser.experiments = orderInformation.experiments;
|
state.applicationUser.experiments = orderInformation.experiments;
|
||||||
|
|
@ -361,8 +366,23 @@ export const mutations = {
|
||||||
},
|
},
|
||||||
updateTriggeredSiteEntry(state, wasSiteEntryTriggered) {
|
updateTriggeredSiteEntry(state, wasSiteEntryTriggered) {
|
||||||
state.applicationUser.triggeredSiteEntry = wasSiteEntryTriggered;
|
state.applicationUser.triggeredSiteEntry = wasSiteEntryTriggered;
|
||||||
}
|
},
|
||||||
}
|
// START GA click event mutations
|
||||||
|
// updateCurrentlySelectedValues(state, groupName, value) {
|
||||||
|
// state.gaClickInformation.currentlySelectedValues[groupName] = value;
|
||||||
|
// },
|
||||||
|
// updateFiredGaClickEventValues(state, groupName, value) {
|
||||||
|
// state.gaClickInformation.firedGaClickEventValues[groupName] = value;
|
||||||
|
// },
|
||||||
|
// updateLastFocusedInputGroup(state, groupName) {
|
||||||
|
// state.gaClickInformation.lastFocusedInputGroup = groupName;
|
||||||
|
// },
|
||||||
|
// updateWasLastFocusedInputMultiselect(state, wasLastFocusedInputMultiselect) {
|
||||||
|
// state.gaClickInformation.wasLastFocusedInputMultiselect =
|
||||||
|
// wasLastFocusedInputMultiselect;
|
||||||
|
// },
|
||||||
|
// END GA click event mutations
|
||||||
|
};
|
||||||
|
|
||||||
// Export Getters
|
// Export Getters
|
||||||
export const getters = {
|
export const getters = {
|
||||||
|
|
@ -378,7 +398,9 @@ export const getters = {
|
||||||
eventBus: (state) => state.applicationUser.eventBus,
|
eventBus: (state) => state.applicationUser.eventBus,
|
||||||
damage: (state) => state.order.damage,
|
damage: (state) => state.order.damage,
|
||||||
lineItems: (state) => state.order.lineItems,
|
lineItems: (state) => state.order.lineItems,
|
||||||
pageData: (state) => (page) => { return state.applicationUser.pageData[page]; },
|
pageData: (state) => (page) => {
|
||||||
|
return state.applicationUser.pageData[page];
|
||||||
|
},
|
||||||
applicationUser: (state) => state.applicationUser,
|
applicationUser: (state) => state.applicationUser,
|
||||||
order: (state) => state.order,
|
order: (state) => state.order,
|
||||||
payment: (state) => state.order.payment,
|
payment: (state) => state.order.payment,
|
||||||
|
|
@ -395,29 +417,33 @@ export const getters = {
|
||||||
funnelServiceState: state.order.serviceLocation.state,
|
funnelServiceState: state.order.serviceLocation.state,
|
||||||
funnelServiceZipCode: state.order.serviceLocation.zipCode,
|
funnelServiceZipCode: state.order.serviceLocation.zipCode,
|
||||||
funnelParentAccountNumber: state.order.accountNumber,
|
funnelParentAccountNumber: state.order.accountNumber,
|
||||||
funnelIsCoverageVerified: state.order.payment.insuranceCoverage.isVerified,
|
funnelIsCoverageVerified:
|
||||||
|
state.order.payment.insuranceCoverage.isVerified,
|
||||||
funnelHasRecalibrationPart: getHasRecalibrationPart(state),
|
funnelHasRecalibrationPart: getHasRecalibrationPart(state),
|
||||||
funnelSelectedMultiGlass: state.order.damage.glassToReplace?.length > 1,
|
funnelSelectedMultiGlass: state.order.damage.glassToReplace?.length > 1,
|
||||||
funnelSelectedWindshieldGlass: getAllValuesOfPropertyInArrayOfObjects(state.order.damage.glassToReplace, "glassLocation").includes(damageLocationsSelected.WINDSHIELD),
|
funnelSelectedWindshieldGlass: getNonFalseValuesOfPropertyInArrayOfObjects(state.order.damage.glassToReplace, "glassLocation").includes(damageLocationsSelected.WINDSHIELD),
|
||||||
funnelSelectedBackGlass: getAllValuesOfPropertyInArrayOfObjects(state.order.damage.glassToReplace, "glassLocation").includes(damageLocationsSelected.REAR),
|
funnelSelectedBackGlass: getNonFalseValuesOfPropertyInArrayOfObjects(state.order.damage.glassToReplace, "glassLocation").includes(damageLocationsSelected.REAR),
|
||||||
funnelSelectedDriverSideGlass: getAllValuesOfPropertyInArrayOfObjects(state.order.damage.glassToReplace, "glassLocation").includes(damageLocationsSelected.DRIVER),
|
funnelSelectedDriverSideGlass: getNonFalseValuesOfPropertyInArrayOfObjects(state.order.damage.glassToReplace, "glassLocation").includes(damageLocationsSelected.DRIVER),
|
||||||
funnelSelectedPassengerSideGlass: getAllValuesOfPropertyInArrayOfObjects(state.order.damage.glassToReplace, "glassLocation").includes(damageLocationsSelected.PASSENGER),
|
funnelSelectedPassengerSideGlass: getNonFalseValuesOfPropertyInArrayOfObjects(state.order.damage.glassToReplace, "glassLocation").includes(damageLocationsSelected.PASSENGER),
|
||||||
|
|
||||||
funnelOrderPartNumbers: [...getAllValuesOfPropertyInArrayOfObjects(state.order.lineItems.glassParts, "partNumber"), ...getAllValuesOfPropertyInArrayOfObjects(state.order.lineItems.otherParts, "partNumber")],
|
funnelOrderPartNumbers: [...getNonFalseValuesOfPropertyInArrayOfObjects(state.order.lineItems.glassParts, "partNumber"), ...getNonFalseValuesOfPropertyInArrayOfObjects(state.order.lineItems.otherParts, "partNumber")],
|
||||||
|
|
||||||
funnelOrderPartTypes: [...getAllValuesOfPropertyInArrayOfObjects(state.order.lineItems.glassParts, "recalibrationType"), ...getAllValuesOfPropertyInArrayOfObjects(state.order.lineItems.otherParts, "recalibrationType")],
|
funnelOrderPartTypes: [...getNonFalseValuesOfPropertyInArrayOfObjects(state.order.lineItems.glassParts, "recalibrationType"), ...getNonFalseValuesOfPropertyInArrayOfObjects(state.order.lineItems.otherParts, "recalibrationType")],
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
experimentSettings: (state) => state.applicationUser.experiments.map(x => x.settings).reduce((r, c) => Object.assign(r, c), {}) ?? {}
|
experimentSettings: (state) =>
|
||||||
}
|
state.applicationUser.experiments
|
||||||
|
.map((x) => x.settings)
|
||||||
|
.reduce((r, c) => Object.assign(r, c), {}) ?? {},
|
||||||
|
// gaClickInformation: (state) => state.gaClickInformation,
|
||||||
|
};
|
||||||
|
|
||||||
function getAllValuesOfPropertyInArrayOfObjects(array, propertyName) {
|
function getNonFalseValuesOfPropertyInArrayOfObjects(array, propertyName) {
|
||||||
return (array ?? []).map(x => x[propertyName]).filter(x => x);
|
return (array ?? []).map(x => x[propertyName]).filter(x => x);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Export Actions
|
// Export Actions
|
||||||
export const actions = {
|
export const actions = {
|
||||||
|
|
||||||
// Vehicle API Actions
|
// Vehicle API Actions
|
||||||
getVehicleYears(context) {
|
getVehicleYears(context) {
|
||||||
return globalMethods.callHttpClient({
|
return globalMethods.callHttpClient({
|
||||||
|
|
@ -448,11 +474,14 @@ export const actions = {
|
||||||
endpoint: endpoints.LookupVinByPlate.url,
|
endpoint: endpoints.LookupVinByPlate.url,
|
||||||
payload: {
|
payload: {
|
||||||
licensePlate: licensePlate,
|
licensePlate: licensePlate,
|
||||||
licenseState: licenseState
|
licenseState: licenseState,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
lookupVinByAddress(context, { licenseLastName, licenseStreetAddress, licenseZip, licenseState }) {
|
lookupVinByAddress(
|
||||||
|
context,
|
||||||
|
{ licenseLastName, licenseStreetAddress, licenseZip, licenseState }
|
||||||
|
) {
|
||||||
return globalMethods.callHttpClient({
|
return globalMethods.callHttpClient({
|
||||||
method: endpoints.LookupVinByAddress.method,
|
method: endpoints.LookupVinByAddress.method,
|
||||||
endpoint: endpoints.LookupVinByAddress.url,
|
endpoint: endpoints.LookupVinByAddress.url,
|
||||||
|
|
@ -460,7 +489,7 @@ export const actions = {
|
||||||
licenseLastName: licenseLastName,
|
licenseLastName: licenseLastName,
|
||||||
licenseStreetAddress: licenseStreetAddress,
|
licenseStreetAddress: licenseStreetAddress,
|
||||||
licenseZip: licenseZip,
|
licenseZip: licenseZip,
|
||||||
licenseState: licenseState
|
licenseState: licenseState,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
@ -494,10 +523,22 @@ export const actions = {
|
||||||
})
|
})
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
context.commit(storeMutations.UPDATE_CAR_ID, response.data.carId);
|
context.commit(storeMutations.UPDATE_CAR_ID, response.data.carId);
|
||||||
context.commit(storeMutations.UPDATE_VEHICLE_CATEGORY, response.data.category);
|
context.commit(
|
||||||
context.commit(storeMutations.UPDATE_VEHICLE_IMAGE_URL, response.data.imageUrl);
|
storeMutations.UPDATE_VEHICLE_CATEGORY,
|
||||||
context.commit(storeMutations.UPDATE_VEHICLE_IMAGE_VIF_NUMBER, response.data.imageVifNumber);
|
response.data.category
|
||||||
context.commit(storeMutations.UPDATE_VEHICLE_IMAGE_COLOR, response.data.imageVifColor);
|
);
|
||||||
|
context.commit(
|
||||||
|
storeMutations.UPDATE_VEHICLE_IMAGE_URL,
|
||||||
|
response.data.imageUrl
|
||||||
|
);
|
||||||
|
context.commit(
|
||||||
|
storeMutations.UPDATE_VEHICLE_IMAGE_VIF_NUMBER,
|
||||||
|
response.data.imageVifNumber
|
||||||
|
);
|
||||||
|
context.commit(
|
||||||
|
storeMutations.UPDATE_VEHICLE_IMAGE_COLOR,
|
||||||
|
response.data.imageVifColor
|
||||||
|
);
|
||||||
return response;
|
return response;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
@ -511,8 +552,8 @@ export const actions = {
|
||||||
validateZip(context, { zip }) {
|
validateZip(context, { zip }) {
|
||||||
return globalMethods.callHttpClient({
|
return globalMethods.callHttpClient({
|
||||||
methods: endpoints.ValidateZip.method,
|
methods: endpoints.ValidateZip.method,
|
||||||
endpoint: `${endpoints.ValidateZip.url}/${zip}`
|
endpoint: `${endpoints.ValidateZip.url}/${zip}`,
|
||||||
})
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
// Dependency Actions
|
// Dependency Actions
|
||||||
|
|
@ -527,7 +568,7 @@ export const actions = {
|
||||||
},
|
},
|
||||||
resetRegistrationAndDependencies(context) {
|
resetRegistrationAndDependencies(context) {
|
||||||
context.commit(storeMutations.RESET_REGISTRATION_STATE);
|
context.commit(storeMutations.RESET_REGISTRATION_STATE);
|
||||||
context.commit(storeMutations.RESET_GLASS_PARTS_STATE)
|
context.commit(storeMutations.RESET_GLASS_PARTS_STATE);
|
||||||
},
|
},
|
||||||
resetPartsAndDependencies(context) {
|
resetPartsAndDependencies(context) {
|
||||||
context.commit(storeMutations.RESET_GLASS_PARTS_STATE);
|
context.commit(storeMutations.RESET_GLASS_PARTS_STATE);
|
||||||
|
|
@ -583,8 +624,8 @@ export const actions = {
|
||||||
assignmentId: experiment.assignmentId,
|
assignmentId: experiment.assignmentId,
|
||||||
sessionKey: sessionKey,
|
sessionKey: sessionKey,
|
||||||
pageName: pageName,
|
pageName: pageName,
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -592,13 +633,28 @@ export const actions = {
|
||||||
updateStoreWithSaveSessionResponse(context, { referralNumber, referralDate, referralCorrelationId, eon, accountNumber, savedSessionId, crmCustomerId }) {
|
updateStoreWithSaveSessionResponse(context, { referralNumber, referralDate, referralCorrelationId, eon, accountNumber, savedSessionId, crmCustomerId }) {
|
||||||
context.commit(storeMutations.UPDATE_REFERRAL_NUMBER, referralNumber);
|
context.commit(storeMutations.UPDATE_REFERRAL_NUMBER, referralNumber);
|
||||||
context.commit(storeMutations.UPDATE_REFERRAL_DATE, referralDate);
|
context.commit(storeMutations.UPDATE_REFERRAL_DATE, referralDate);
|
||||||
context.commit(storeMutations.UPDATE_REFERRAL_CORRELATION_ID, referralCorrelationId);
|
context.commit(
|
||||||
|
storeMutations.UPDATE_REFERRAL_CORRELATION_ID,
|
||||||
|
referralCorrelationId
|
||||||
|
);
|
||||||
context.commit(storeMutations.UPDATE_EON, eon);
|
context.commit(storeMutations.UPDATE_EON, eon);
|
||||||
context.commit(storeMutations.UPDATE_PARENT_ACCT_NUMBER, accountNumber);
|
context.commit(storeMutations.UPDATE_PARENT_ACCT_NUMBER, accountNumber);
|
||||||
context.commit(storeMutations.UPDATE_SAVED_SESSION_ID, savedSessionId);
|
context.commit(storeMutations.UPDATE_SAVED_SESSION_ID, savedSessionId);
|
||||||
context.commit(storeMutations.UPDATE_CRM_CUSTOMER_ID, crmCustomerId);
|
context.commit(storeMutations.UPDATE_CRM_CUSTOMER_ID, crmCustomerId);
|
||||||
},
|
},
|
||||||
logPageView(context, { userId, sessionKey, pageName, sessionId, action, event, shouldUseSessionId, experimentsForUser }) {
|
logPageView(
|
||||||
|
context,
|
||||||
|
{
|
||||||
|
userId,
|
||||||
|
sessionKey,
|
||||||
|
pageName,
|
||||||
|
sessionId,
|
||||||
|
action,
|
||||||
|
event,
|
||||||
|
shouldUseSessionId,
|
||||||
|
experimentsForUser,
|
||||||
|
}
|
||||||
|
) {
|
||||||
var payload = {
|
var payload = {
|
||||||
userId: userId,
|
userId: userId,
|
||||||
sessionKey: sessionKey,
|
sessionKey: sessionKey,
|
||||||
|
|
@ -608,17 +664,31 @@ export const actions = {
|
||||||
action: action,
|
action: action,
|
||||||
event: event,
|
event: event,
|
||||||
shouldUseSessionId: shouldUseSessionId,
|
shouldUseSessionId: shouldUseSessionId,
|
||||||
experimentsForUser: experimentsForUser
|
experimentsForUser: experimentsForUser,
|
||||||
};
|
};
|
||||||
|
|
||||||
return globalMethods.callHttpClient({
|
return globalMethods.callHttpClient({
|
||||||
method: endpoints.LogPageView.method,
|
method: endpoints.LogPageView.method,
|
||||||
endpoint: endpoints.LogPageView.url,
|
endpoint: endpoints.LogPageView.url,
|
||||||
payload: payload,
|
payload: payload,
|
||||||
logApiCall: false
|
logApiCall: false,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
logCustomEvent(context, { userId, sessionKey, pageName, sessionId, category, action, label, value, shouldUseSessionId, experimentsForUser }) {
|
logCustomEvent(
|
||||||
|
context,
|
||||||
|
{
|
||||||
|
userId,
|
||||||
|
sessionKey,
|
||||||
|
pageName,
|
||||||
|
sessionId,
|
||||||
|
category,
|
||||||
|
action,
|
||||||
|
label,
|
||||||
|
value,
|
||||||
|
shouldUseSessionId,
|
||||||
|
experimentsForUser,
|
||||||
|
}
|
||||||
|
) {
|
||||||
var payload = {
|
var payload = {
|
||||||
userId: userId,
|
userId: userId,
|
||||||
sessionKey: sessionKey,
|
sessionKey: sessionKey,
|
||||||
|
|
@ -630,14 +700,14 @@ export const actions = {
|
||||||
label: label,
|
label: label,
|
||||||
value: value,
|
value: value,
|
||||||
shouldUseSessionId: shouldUseSessionId,
|
shouldUseSessionId: shouldUseSessionId,
|
||||||
experimentsForUser: experimentsForUser
|
experimentsForUser: experimentsForUser,
|
||||||
};
|
};
|
||||||
|
|
||||||
return globalMethods.callHttpClient({
|
return globalMethods.callHttpClient({
|
||||||
method: endpoints.LogCustomEvent.method,
|
method: endpoints.LogCustomEvent.method,
|
||||||
endpoint: endpoints.LogCustomEvent.url,
|
endpoint: endpoints.LogCustomEvent.url,
|
||||||
payload: payload,
|
payload: payload,
|
||||||
logApiCall: false
|
logApiCall: false,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
initializeSession(context, { userId, sessionId, userAgent, referrer }) {
|
initializeSession(context, { userId, sessionId, userAgent, referrer }) {
|
||||||
|
|
@ -649,22 +719,28 @@ export const actions = {
|
||||||
userAgent: userAgent,
|
userAgent: userAgent,
|
||||||
operatorId: "WEB",
|
operatorId: "WEB",
|
||||||
userName: "SafeliteConceptFunnel",
|
userName: "SafeliteConceptFunnel",
|
||||||
referrer: referrer
|
referrer: referrer,
|
||||||
};
|
};
|
||||||
|
|
||||||
return globalMethods.callHttpClient({
|
return globalMethods.callHttpClient({
|
||||||
method: endpoints.InitializeSession.method,
|
method: endpoints.InitializeSession.method,
|
||||||
endpoint: endpoints.InitializeSession.url,
|
endpoint: endpoints.InitializeSession.url,
|
||||||
payload: payload,
|
payload: payload,
|
||||||
logApiCall: false
|
logApiCall: false,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
// Misc Actions
|
// Misc Actions
|
||||||
setReferralInformation(context, { referralNumber, referralDate, referralCorrelationId, eon }) {
|
setReferralInformation(
|
||||||
|
context,
|
||||||
|
{ referralNumber, referralDate, referralCorrelationId, eon }
|
||||||
|
) {
|
||||||
context.commit(storeMutations.UPDATE_REFERRAL_NUMBER, referralNumber);
|
context.commit(storeMutations.UPDATE_REFERRAL_NUMBER, referralNumber);
|
||||||
context.commit(storeMutations.UPDATE_REFERRAL_DATE, referralDate);
|
context.commit(storeMutations.UPDATE_REFERRAL_DATE, referralDate);
|
||||||
context.commit(storeMutations.UPDATE_REFERRAL_CORRELATION_ID, referralCorrelationId);
|
context.commit(
|
||||||
|
storeMutations.UPDATE_REFERRAL_CORRELATION_ID,
|
||||||
|
referralCorrelationId
|
||||||
|
);
|
||||||
context.commit(storeMutations.UPDATE_EON, eon);
|
context.commit(storeMutations.UPDATE_EON, eon);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -672,11 +748,14 @@ export const actions = {
|
||||||
return globalMethods.callHttpClient({
|
return globalMethods.callHttpClient({
|
||||||
method: endpoints.GetExperimentsByUser.method,
|
method: endpoints.GetExperimentsByUser.method,
|
||||||
endpoint: `${endpoints.GetExperimentsByUser.url}/${userId}`,
|
endpoint: `${endpoints.GetExperimentsByUser.url}/${userId}`,
|
||||||
payload: {}
|
payload: {},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
async runExperimentsForTrigger(context, { userId, triggerEvent, triggerValue }) {
|
async runExperimentsForTrigger(
|
||||||
|
context,
|
||||||
|
{ userId, triggerEvent, triggerValue }
|
||||||
|
) {
|
||||||
if (triggerEvent == experimentTriggers.SITE_ENTRY) {
|
if (triggerEvent == experimentTriggers.SITE_ENTRY) {
|
||||||
context.commit(storeMutations.UPDATE_TRIGGERED_SITE_ENTRY, true);
|
context.commit(storeMutations.UPDATE_TRIGGERED_SITE_ENTRY, true);
|
||||||
}
|
}
|
||||||
|
|
@ -686,7 +765,7 @@ export const actions = {
|
||||||
userId: userId,
|
userId: userId,
|
||||||
triggerEvent: triggerEvent,
|
triggerEvent: triggerEvent,
|
||||||
triggerValue: triggerValue,
|
triggerValue: triggerValue,
|
||||||
experimentOrder: context.getters.experimentOrder
|
experimentOrder: context.getters.experimentOrder,
|
||||||
};
|
};
|
||||||
|
|
||||||
const response = await globalMethods.callHttpClient({
|
const response = await globalMethods.callHttpClient({
|
||||||
|
|
@ -695,7 +774,10 @@ export const actions = {
|
||||||
payload: payload,
|
payload: payload,
|
||||||
});
|
});
|
||||||
|
|
||||||
context.commit(storeMutations.UPDATE_EXPERIMENTS, response.data.experiments);
|
context.commit(
|
||||||
|
storeMutations.UPDATE_EXPERIMENTS,
|
||||||
|
response.data.experiments
|
||||||
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
getEvoxImage(context, { relativeUrl }) {
|
getEvoxImage(context, { relativeUrl }) {
|
||||||
|
|
@ -724,7 +806,7 @@ export const actions = {
|
||||||
carId: carId,
|
carId: carId,
|
||||||
glass: glassArray ?? [],
|
glass: glassArray ?? [],
|
||||||
zip: zipCode,
|
zip: zipCode,
|
||||||
vin: vin
|
vin: vin,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
@ -749,7 +831,7 @@ export const actions = {
|
||||||
glass: glassArray,
|
glass: glassArray,
|
||||||
answerResults: resultsArray,
|
answerResults: resultsArray,
|
||||||
zip: zipCode,
|
zip: zipCode,
|
||||||
vin: vin
|
vin: vin,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
@ -758,24 +840,31 @@ export const actions = {
|
||||||
return globalMethods.callHttpClient({
|
return globalMethods.callHttpClient({
|
||||||
method: endpoints.GetCapabilityQuestions.method,
|
method: endpoints.GetCapabilityQuestions.method,
|
||||||
endpoint: `${endpoints.GetCapabilityQuestions.url}/${carId}/${partNumber}`,
|
endpoint: `${endpoints.GetCapabilityQuestions.url}/${carId}/${partNumber}`,
|
||||||
})
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
getPartFromCapabilityQuestionAnswer(context, glassLocation) {
|
getPartFromCapabilityQuestionAnswer(context, glassLocation) {
|
||||||
const pageData = context.getters.pageData(fmgPageValues.CAPABILITY_QUESTIONS);
|
const pageData = context.getters.pageData(
|
||||||
|
fmgPageValues.CAPABILITY_QUESTIONS
|
||||||
|
);
|
||||||
|
|
||||||
const part = pageData.partsOrQuestions.find(x => x.glassLocation === glassLocation).parts[0];
|
const part = pageData.partsOrQuestions.find(
|
||||||
const capabilityQuestionAnswers = context.getters.damage.capabilityQuestionAnswers;
|
(x) => x.glassLocation === glassLocation
|
||||||
const capabilityQuestionAnswersForPart = capabilityQuestionAnswers.find(x => x.glassLocation === glassLocation);
|
).parts[0];
|
||||||
|
const capabilityQuestionAnswers =
|
||||||
|
context.getters.damage.capabilityQuestionAnswers;
|
||||||
|
const capabilityQuestionAnswersForPart = capabilityQuestionAnswers.find(
|
||||||
|
(x) => x.glassLocation === glassLocation
|
||||||
|
);
|
||||||
|
|
||||||
return globalMethods.callHttpClient({
|
return globalMethods.callHttpClient({
|
||||||
method: endpoints.GetPartFromCapabilityAnswer.method,
|
method: endpoints.GetPartFromCapabilityAnswer.method,
|
||||||
endpoint: endpoints.GetPartFromCapabilityAnswer.url,
|
endpoint: endpoints.GetPartFromCapabilityAnswer.url,
|
||||||
payload: {
|
payload: {
|
||||||
part,
|
part,
|
||||||
capabilityAnswerResults: capabilityQuestionAnswersForPart
|
capabilityAnswerResults: capabilityQuestionAnswersForPart,
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
// Session API Actions
|
// Session API Actions
|
||||||
|
|
@ -810,21 +899,21 @@ export const actions = {
|
||||||
damage: {
|
damage: {
|
||||||
numberOfChips: damage.numberOfChips,
|
numberOfChips: damage.numberOfChips,
|
||||||
glassToReplace: damage.glassToReplace,
|
glassToReplace: damage.glassToReplace,
|
||||||
isRepair: damage.isRepair
|
isRepair: damage.isRepair,
|
||||||
},
|
},
|
||||||
customer: {
|
customer: {
|
||||||
emailAddress: order.customer.emailAddress,
|
emailAddress: order.customer.emailAddress,
|
||||||
},
|
},
|
||||||
lineItems: {
|
lineItems: {
|
||||||
glassParts: lineItems.glassParts
|
glassParts: lineItems.glassParts,
|
||||||
},
|
},
|
||||||
serviceLocation: {
|
serviceLocation: {
|
||||||
streetAddress: order.serviceLocation.address,
|
streetAddress: order.serviceLocation.address,
|
||||||
city: order.serviceLocation.city,
|
city: order.serviceLocation.city,
|
||||||
state: order.serviceLocation.state,
|
state: order.serviceLocation.state,
|
||||||
zipCode: order.serviceLocation.zipCode
|
zipCode: order.serviceLocation.zipCode,
|
||||||
},
|
},
|
||||||
referralNumber: order.referralNumber?.toString(), // TODO It'd be nice to save these as strings in the first place
|
referralNumber: order.referralNumber?.toString(), // TODO It'd be nice to save these as strings in the first place
|
||||||
referralDate: order.referralDate,
|
referralDate: order.referralDate,
|
||||||
accountNumber: order.accountNumber?.toString(),
|
accountNumber: order.accountNumber?.toString(),
|
||||||
existingPromoCode: null,
|
existingPromoCode: null,
|
||||||
|
|
@ -859,7 +948,6 @@ export const actions = {
|
||||||
|
|
||||||
// Vehicle
|
// Vehicle
|
||||||
saveVehicleYear(context, year) {
|
saveVehicleYear(context, year) {
|
||||||
|
|
||||||
//Reset dependent state when changing
|
//Reset dependent state when changing
|
||||||
if (context.state.order.vehicle.year !== year) {
|
if (context.state.order.vehicle.year !== year) {
|
||||||
context.commit(storeMutations.UPDATE_MAKE, null);
|
context.commit(storeMutations.UPDATE_MAKE, null);
|
||||||
|
|
@ -881,7 +969,6 @@ export const actions = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
saveVehicleMake(context, make) {
|
saveVehicleMake(context, make) {
|
||||||
|
|
||||||
//Reset dependent state when changing
|
//Reset dependent state when changing
|
||||||
if (context.state.order.vehicle.make !== make) {
|
if (context.state.order.vehicle.make !== make) {
|
||||||
context.commit(storeMutations.UPDATE_MODEL, null);
|
context.commit(storeMutations.UPDATE_MODEL, null);
|
||||||
|
|
@ -902,7 +989,6 @@ export const actions = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
saveVehicleModel(context, model) {
|
saveVehicleModel(context, model) {
|
||||||
|
|
||||||
//Reset dependent state when changing
|
//Reset dependent state when changing
|
||||||
if (context.state.order.vehicle.model !== model) {
|
if (context.state.order.vehicle.model !== model) {
|
||||||
context.commit(storeMutations.UPDATE_STYLE, null);
|
context.commit(storeMutations.UPDATE_STYLE, null);
|
||||||
|
|
@ -939,20 +1025,35 @@ export const actions = {
|
||||||
context.commit(storeMutations.UPDATE_STYLE, style);
|
context.commit(storeMutations.UPDATE_STYLE, style);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
saveVehicleDamage(context, { isWindshieldRepair, selectedGlassToReplace, selectedWindshieldChipCount }) {
|
saveVehicleDamage(
|
||||||
|
context,
|
||||||
|
{ isWindshieldRepair, selectedGlassToReplace, selectedWindshieldChipCount }
|
||||||
|
) {
|
||||||
const selectedGlassPassedInSorted = selectedGlassToReplace.slice().sort();
|
const selectedGlassPassedInSorted = selectedGlassToReplace.slice().sort();
|
||||||
const isGlassToReplaceTheSame = (context.state.order.damage.glassToReplace?.length === selectedGlassToReplace.length)
|
const isGlassToReplaceTheSame =
|
||||||
&& context.state.order.damage.glassToReplace
|
context.state.order.damage.glassToReplace?.length ===
|
||||||
|
selectedGlassToReplace.length &&
|
||||||
|
context.state.order.damage.glassToReplace
|
||||||
.slice()
|
.slice()
|
||||||
.sort()
|
.sort()
|
||||||
.every((obj, index) => obj.glassLocation === selectedGlassPassedInSorted[index].glassLocation && obj.glassName === selectedGlassPassedInSorted[index].glassName);
|
.every(
|
||||||
const isWindshieldRepairTheSame = isWindshieldRepair === context.state.order.damage.isRepair;
|
(obj, index) =>
|
||||||
|
obj.glassLocation ===
|
||||||
|
selectedGlassPassedInSorted[index].glassLocation &&
|
||||||
|
obj.glassName === selectedGlassPassedInSorted[index].glassName
|
||||||
|
);
|
||||||
|
const isWindshieldRepairTheSame =
|
||||||
|
isWindshieldRepair === context.state.order.damage.isRepair;
|
||||||
const isChipCountTheSame = Array.isArray(selectedWindshieldChipCount) //TODO: fix the underlying components so this is never an array
|
const isChipCountTheSame = Array.isArray(selectedWindshieldChipCount) //TODO: fix the underlying components so this is never an array
|
||||||
? selectedWindshieldChipCount[0] === context.state.order.damage.numberOfChips
|
? selectedWindshieldChipCount[0] ===
|
||||||
: selectedWindshieldChipCount === context.state.order.damage.numberOfChips;
|
context.state.order.damage.numberOfChips
|
||||||
|
: selectedWindshieldChipCount ===
|
||||||
|
context.state.order.damage.numberOfChips;
|
||||||
|
|
||||||
const isDamageChanging = !isGlassToReplaceTheSame || !isWindshieldRepairTheSame || (isWindshieldRepair && !isChipCountTheSame);
|
const isDamageChanging =
|
||||||
|
!isGlassToReplaceTheSame ||
|
||||||
|
!isWindshieldRepairTheSame ||
|
||||||
|
(isWindshieldRepair && !isChipCountTheSame);
|
||||||
|
|
||||||
if (isDamageChanging) {
|
if (isDamageChanging) {
|
||||||
//Reset dependent state when changing
|
//Reset dependent state when changing
|
||||||
|
|
@ -960,13 +1061,22 @@ export const actions = {
|
||||||
|
|
||||||
// Save new values
|
// Save new values
|
||||||
context.commit(storeMutations.UPDATE_IS_REPAIR, isWindshieldRepair);
|
context.commit(storeMutations.UPDATE_IS_REPAIR, isWindshieldRepair);
|
||||||
context.commit(storeMutations.UPDATE_NUMBER_OF_CHIPS, isWindshieldRepair ? parseInt(selectedWindshieldChipCount) : null);
|
context.commit(
|
||||||
context.commit(storeMutations.UPDATE_GLASS_TO_REPLACE, selectedGlassToReplace);
|
storeMutations.UPDATE_NUMBER_OF_CHIPS,
|
||||||
|
isWindshieldRepair ? parseInt(selectedWindshieldChipCount) : null
|
||||||
|
);
|
||||||
|
context.commit(
|
||||||
|
storeMutations.UPDATE_GLASS_TO_REPLACE,
|
||||||
|
selectedGlassToReplace
|
||||||
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// Vin lookup
|
// Vin lookup
|
||||||
saveVinLookup(context, { isSelectedGlassAvailableForVehicle, vehicleInfo, registrationInfo }) {
|
saveVinLookup(
|
||||||
|
context,
|
||||||
|
{ isSelectedGlassAvailableForVehicle, vehicleInfo, registrationInfo }
|
||||||
|
) {
|
||||||
//Reset dependent state when changing
|
//Reset dependent state when changing
|
||||||
if (vehicleInfo.vin !== context.state.order.vehicle.vin) {
|
if (vehicleInfo.vin !== context.state.order.vehicle.vin) {
|
||||||
context.dispatch(storeActions.RESET_REGISTRATION_STATE_AND_DEPENDENCIES);
|
context.dispatch(storeActions.RESET_REGISTRATION_STATE_AND_DEPENDENCIES);
|
||||||
|
|
@ -981,10 +1091,15 @@ export const actions = {
|
||||||
context.commit(storeMutations.UPDATE_REGISTRATION, registrationInfo);
|
context.commit(storeMutations.UPDATE_REGISTRATION, registrationInfo);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
saveRegistrationLicensePlateLookup(context, { isSelectedGlassAvailableForVehicle, vehicleInfo, registrationInfo }) {
|
saveRegistrationLicensePlateLookup(
|
||||||
|
context,
|
||||||
|
{ isSelectedGlassAvailableForVehicle, vehicleInfo, registrationInfo }
|
||||||
|
) {
|
||||||
//Reset dependent state when changing
|
//Reset dependent state when changing
|
||||||
if (registrationInfo?.licensePlate !== context.state.order.vehicle.registration?.licensePlate) {
|
if (
|
||||||
|
registrationInfo?.licensePlate !==
|
||||||
|
context.state.order.vehicle.registration?.licensePlate
|
||||||
|
) {
|
||||||
context.dispatch(storeActions.RESET_REGISTRATION_STATE_AND_DEPENDENCIES);
|
context.dispatch(storeActions.RESET_REGISTRATION_STATE_AND_DEPENDENCIES);
|
||||||
|
|
||||||
if (!isSelectedGlassAvailableForVehicle) {
|
if (!isSelectedGlassAvailableForVehicle) {
|
||||||
|
|
@ -997,10 +1112,25 @@ export const actions = {
|
||||||
context.commit(storeMutations.UPDATE_REGISTRATION, registrationInfo);
|
context.commit(storeMutations.UPDATE_REGISTRATION, registrationInfo);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
saveRegistrationAddressLookup(context, { isSelectedGlassAvailableForVehicle, vehicleInfo, registrationInfo }) {
|
saveRegistrationAddressLookup(
|
||||||
|
context,
|
||||||
|
{ isSelectedGlassAvailableForVehicle, vehicleInfo, registrationInfo }
|
||||||
|
) {
|
||||||
//Reset dependent state when changing
|
//Reset dependent state when changing
|
||||||
if (registrationInfo?.address !== context.state.order.vehicle.registration?.address || registrationInfo?.city !== context.state.order.vehicle.registration?.city || registrationInfo?.state !== context.state.order.vehicle.registration?.state || registrationInfo?.zipCode !== context.state.order.vehicle.registration?.zipCode || registrationInfo?.firstName !== context.state.order.vehicle.registration?.firstName || registrationInfo?.lastName !== context.state.order.vehicle.registration?.lastName) {
|
if (
|
||||||
|
registrationInfo?.address !==
|
||||||
|
context.state.order.vehicle.registration?.address ||
|
||||||
|
registrationInfo?.city !==
|
||||||
|
context.state.order.vehicle.registration?.city ||
|
||||||
|
registrationInfo?.state !==
|
||||||
|
context.state.order.vehicle.registration?.state ||
|
||||||
|
registrationInfo?.zipCode !==
|
||||||
|
context.state.order.vehicle.registration?.zipCode ||
|
||||||
|
registrationInfo?.firstName !==
|
||||||
|
context.state.order.vehicle.registration?.firstName ||
|
||||||
|
registrationInfo?.lastName !==
|
||||||
|
context.state.order.vehicle.registration?.lastName
|
||||||
|
) {
|
||||||
context.dispatch(storeActions.RESET_REGISTRATION_STATE_AND_DEPENDENCIES);
|
context.dispatch(storeActions.RESET_REGISTRATION_STATE_AND_DEPENDENCIES);
|
||||||
|
|
||||||
if (!isSelectedGlassAvailableForVehicle) {
|
if (!isSelectedGlassAvailableForVehicle) {
|
||||||
|
|
@ -1015,72 +1145,141 @@ export const actions = {
|
||||||
},
|
},
|
||||||
savePartQuestionAnswers(context, partQuestionAnswersArray) {
|
savePartQuestionAnswers(context, partQuestionAnswersArray) {
|
||||||
// if part question answers have changed, reset subsequent question answers
|
// if part question answers have changed, reset subsequent question answers
|
||||||
const sortedPreviousResultsArray = sortArrayOfObjectsByPropertyValue(context.getters.damage.partQuestionAnswers, "result");
|
const sortedPreviousResultsArray = sortArrayOfObjectsByPropertyValue(
|
||||||
const sortedPartQuestionAnswersArray = sortArrayOfObjectsByPropertyValue(partQuestionAnswersArray, "result")
|
context.getters.damage.partQuestionAnswers,
|
||||||
const havePartQuestionAnswersChanged = sortedPreviousResultsArray?.length !== sortedPartQuestionAnswersArray.length ||
|
"result"
|
||||||
!sortedPreviousResultsArray?.every((x, i) => x.result === sortedPartQuestionAnswersArray[i].result);
|
);
|
||||||
|
const sortedPartQuestionAnswersArray = sortArrayOfObjectsByPropertyValue(
|
||||||
|
partQuestionAnswersArray,
|
||||||
|
"result"
|
||||||
|
);
|
||||||
|
const havePartQuestionAnswersChanged =
|
||||||
|
sortedPreviousResultsArray?.length !==
|
||||||
|
sortedPartQuestionAnswersArray.length ||
|
||||||
|
!sortedPreviousResultsArray?.every(
|
||||||
|
(x, i) => x.result === sortedPartQuestionAnswersArray[i].result
|
||||||
|
);
|
||||||
|
|
||||||
if (havePartQuestionAnswersChanged) {
|
if (havePartQuestionAnswersChanged) {
|
||||||
context.commit(storeMutations.UPDATE_GLASS_PARTS, null);
|
context.commit(storeMutations.UPDATE_GLASS_PARTS, null);
|
||||||
context.commit(storeMutations.UPDATE_MOLDING_QUESTION_ANSWERS, null);
|
context.commit(storeMutations.UPDATE_MOLDING_QUESTION_ANSWERS, null);
|
||||||
context.commit(storeMutations.UPDATE_CAPABILITY_QUESTION_ANSWERS, null);
|
context.commit(storeMutations.UPDATE_CAPABILITY_QUESTION_ANSWERS, null);
|
||||||
context.commit(storeMutations.UPDATE_PAGE_DATA, { page: fmgPageValues.VEHICLE_PARTS, data: null });
|
context.commit(storeMutations.UPDATE_PAGE_DATA, {
|
||||||
context.commit(storeMutations.UPDATE_PAGE_DATA, { page: fmgPageValues.MOLDING_QUESTIONS, data: null });
|
page: fmgPageValues.VEHICLE_PARTS,
|
||||||
context.commit(storeMutations.UPDATE_PAGE_DATA, { page: fmgPageValues.CAPABILITY_QUESTIONS, data: null });
|
data: null,
|
||||||
|
});
|
||||||
|
context.commit(storeMutations.UPDATE_PAGE_DATA, {
|
||||||
|
page: fmgPageValues.MOLDING_QUESTIONS,
|
||||||
|
data: null,
|
||||||
|
});
|
||||||
|
context.commit(storeMutations.UPDATE_PAGE_DATA, {
|
||||||
|
page: fmgPageValues.CAPABILITY_QUESTIONS,
|
||||||
|
data: null,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
//Save new values
|
//Save new values
|
||||||
context.commit(storeMutations.UPDATE_PART_QUESTION_ANSWERS, partQuestionAnswersArray);
|
context.commit(
|
||||||
|
storeMutations.UPDATE_PART_QUESTION_ANSWERS,
|
||||||
|
partQuestionAnswersArray
|
||||||
|
);
|
||||||
},
|
},
|
||||||
resetMoldingAndCapabilityQuestionAnswersIfNeeded(context, matchedParts) {
|
resetMoldingAndCapabilityQuestionAnswersIfNeeded(context, matchedParts) {
|
||||||
const partsOrQuestionsDataToCompareWith = context.getters.pageData(fmgPageValues.MOLDING_QUESTIONS)?.partsOrQuestions ?? context.getters.pageData(fmgPageValues.CAPABILITY_QUESTIONS)?.partsOrQuestions ?? [];
|
const partsOrQuestionsDataToCompareWith =
|
||||||
|
context.getters.pageData(fmgPageValues.MOLDING_QUESTIONS)
|
||||||
|
?.partsOrQuestions ??
|
||||||
|
context.getters.pageData(fmgPageValues.CAPABILITY_QUESTIONS)
|
||||||
|
?.partsOrQuestions ??
|
||||||
|
[];
|
||||||
|
|
||||||
function getAllPartNumbers(partsOrQuestions) {
|
function getAllPartNumbers(partsOrQuestions) {
|
||||||
return partsOrQuestions[0]?.parts
|
return partsOrQuestions[0]?.parts
|
||||||
? [...partsOrQuestions].map(glass => glass.parts).flat().map(part => part.partNumber).filter(partNumber => !partNumber.toUpperCase().includes("FEE")).sort().join(",")
|
? [...partsOrQuestions]
|
||||||
: []
|
.map((glass) => glass.parts)
|
||||||
|
.flat()
|
||||||
|
.map((part) => part.partNumber)
|
||||||
|
.filter((partNumber) => !partNumber.toUpperCase().includes("FEE"))
|
||||||
|
.sort()
|
||||||
|
.join(",")
|
||||||
|
: [];
|
||||||
}
|
}
|
||||||
|
|
||||||
const previouslySelectedPartNumbers = getAllPartNumbers(partsOrQuestionsDataToCompareWith);
|
const previouslySelectedPartNumbers = getAllPartNumbers(
|
||||||
|
partsOrQuestionsDataToCompareWith
|
||||||
|
);
|
||||||
const currentlySelectedPartNumbers = getAllPartNumbers(matchedParts);
|
const currentlySelectedPartNumbers = getAllPartNumbers(matchedParts);
|
||||||
|
|
||||||
const haveSelectedVehiclePartsChanged = previouslySelectedPartNumbers !== currentlySelectedPartNumbers;
|
const haveSelectedVehiclePartsChanged =
|
||||||
|
previouslySelectedPartNumbers !== currentlySelectedPartNumbers;
|
||||||
|
|
||||||
if (haveSelectedVehiclePartsChanged) {
|
if (haveSelectedVehiclePartsChanged) {
|
||||||
context.commit(storeMutations.UPDATE_GLASS_PARTS, null);
|
context.commit(storeMutations.UPDATE_GLASS_PARTS, null);
|
||||||
context.commit(storeMutations.UPDATE_MOLDING_QUESTION_ANSWERS, null);
|
context.commit(storeMutations.UPDATE_MOLDING_QUESTION_ANSWERS, null);
|
||||||
context.commit(storeMutations.UPDATE_CAPABILITY_QUESTION_ANSWERS, null);
|
context.commit(storeMutations.UPDATE_CAPABILITY_QUESTION_ANSWERS, null);
|
||||||
context.commit(storeMutations.UPDATE_PAGE_DATA, { page: fmgPageValues.MOLDING_QUESTIONS, data: null });
|
context.commit(storeMutations.UPDATE_PAGE_DATA, {
|
||||||
context.commit(storeMutations.UPDATE_PAGE_DATA, { page: fmgPageValues.CAPABILITY_QUESTIONS, data: null });
|
page: fmgPageValues.MOLDING_QUESTIONS,
|
||||||
|
data: null,
|
||||||
|
});
|
||||||
|
context.commit(storeMutations.UPDATE_PAGE_DATA, {
|
||||||
|
page: fmgPageValues.CAPABILITY_QUESTIONS,
|
||||||
|
data: null,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
saveMoldingQuestionAnswers(context, moldingQuestionAnswers) {
|
saveMoldingQuestionAnswers(context, moldingQuestionAnswers) {
|
||||||
const sortedPreviousResultsArray = sortArrayOfObjectsByPropertyValue(context.getters.damage.moldingQuestionAnswers, "partNum");
|
const sortedPreviousResultsArray = sortArrayOfObjectsByPropertyValue(
|
||||||
const sortedMoldingQuestionAnswersArray = sortArrayOfObjectsByPropertyValue(moldingQuestionAnswers, "partNum");
|
context.getters.damage.moldingQuestionAnswers,
|
||||||
const haveMoldingQuestionAnswersChanged = sortedPreviousResultsArray?.length !== sortedMoldingQuestionAnswersArray.length ||
|
"partNum"
|
||||||
!sortedPreviousResultsArray?.every((x, i) => x.partNum === sortedMoldingQuestionAnswersArray[i].partNum);
|
);
|
||||||
|
const sortedMoldingQuestionAnswersArray = sortArrayOfObjectsByPropertyValue(
|
||||||
|
moldingQuestionAnswers,
|
||||||
|
"partNum"
|
||||||
|
);
|
||||||
|
const haveMoldingQuestionAnswersChanged =
|
||||||
|
sortedPreviousResultsArray?.length !==
|
||||||
|
sortedMoldingQuestionAnswersArray.length ||
|
||||||
|
!sortedPreviousResultsArray?.every(
|
||||||
|
(x, i) => x.partNum === sortedMoldingQuestionAnswersArray[i].partNum
|
||||||
|
);
|
||||||
|
|
||||||
if (haveMoldingQuestionAnswersChanged) {
|
if (haveMoldingQuestionAnswersChanged) {
|
||||||
context.commit(storeMutations.UPDATE_GLASS_PARTS, null);
|
context.commit(storeMutations.UPDATE_GLASS_PARTS, null);
|
||||||
context.commit(storeMutations.UPDATE_CAPABILITY_QUESTION_ANSWERS, null);
|
context.commit(storeMutations.UPDATE_CAPABILITY_QUESTION_ANSWERS, null);
|
||||||
context.commit(storeMutations.UPDATE_PAGE_DATA, { page: fmgPageValues.CAPABILITY_QUESTIONS, data: null });
|
context.commit(storeMutations.UPDATE_PAGE_DATA, {
|
||||||
|
page: fmgPageValues.CAPABILITY_QUESTIONS,
|
||||||
|
data: null,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
//Save new values
|
//Save new values
|
||||||
context.commit(storeMutations.UPDATE_MOLDING_QUESTION_ANSWERS, moldingQuestionAnswers);
|
context.commit(
|
||||||
|
storeMutations.UPDATE_MOLDING_QUESTION_ANSWERS,
|
||||||
|
moldingQuestionAnswers
|
||||||
|
);
|
||||||
},
|
},
|
||||||
saveCapabilityQuestionAnswers(context, capabilityQuestionAnswers) {
|
saveCapabilityQuestionAnswers(context, capabilityQuestionAnswers) {
|
||||||
const sortedPreviousResultsArray = sortArrayOfObjectsByPropertyValue(context.getters.damage.capabilityQuestionAnswers, "result");
|
const sortedPreviousResultsArray = sortArrayOfObjectsByPropertyValue(
|
||||||
const sortedCapabilityQuestionAnswersArray = sortArrayOfObjectsByPropertyValue(capabilityQuestionAnswers, "result");
|
context.getters.damage.capabilityQuestionAnswers,
|
||||||
const haveCapabilityQuestionAnswersChanged = sortedPreviousResultsArray?.length !== sortedCapabilityQuestionAnswersArray.length ||
|
"result"
|
||||||
!sortedPreviousResultsArray?.every((x, i) => x.result === sortedCapabilityQuestionAnswersArray[i].result);
|
);
|
||||||
|
const sortedCapabilityQuestionAnswersArray =
|
||||||
|
sortArrayOfObjectsByPropertyValue(capabilityQuestionAnswers, "result");
|
||||||
|
const haveCapabilityQuestionAnswersChanged =
|
||||||
|
sortedPreviousResultsArray?.length !==
|
||||||
|
sortedCapabilityQuestionAnswersArray.length ||
|
||||||
|
!sortedPreviousResultsArray?.every(
|
||||||
|
(x, i) => x.result === sortedCapabilityQuestionAnswersArray[i].result
|
||||||
|
);
|
||||||
|
|
||||||
if (haveCapabilityQuestionAnswersChanged) {
|
if (haveCapabilityQuestionAnswersChanged) {
|
||||||
context.commit(storeMutations.UPDATE_GLASS_PARTS, null);
|
context.commit(storeMutations.UPDATE_GLASS_PARTS, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Save new values
|
//Save new values
|
||||||
context.commit(storeMutations.UPDATE_CAPABILITY_QUESTION_ANSWERS, capabilityQuestionAnswers);
|
context.commit(
|
||||||
|
storeMutations.UPDATE_CAPABILITY_QUESTION_ANSWERS,
|
||||||
|
capabilityQuestionAnswers
|
||||||
|
);
|
||||||
},
|
},
|
||||||
// Misc order actions
|
// Misc order actions
|
||||||
saveServiceLocation(context, serviceLocationInfo) {
|
saveServiceLocation(context, serviceLocationInfo) {
|
||||||
|
|
@ -1092,7 +1291,6 @@ export const actions = {
|
||||||
saveVin(context, { isSelectedGlassAvailableForVehicle, vehicleInfo }) {
|
saveVin(context, { isSelectedGlassAvailableForVehicle, vehicleInfo }) {
|
||||||
//Reset dependent state when changing
|
//Reset dependent state when changing
|
||||||
if (vehicleInfo.vin !== context.state.order.vehicle.vin) {
|
if (vehicleInfo.vin !== context.state.order.vehicle.vin) {
|
||||||
|
|
||||||
if (!isSelectedGlassAvailableForVehicle) {
|
if (!isSelectedGlassAvailableForVehicle) {
|
||||||
context.dispatch(storeActions.RESET_DAMAGE_STATE_AND_DEPENDENCIES);
|
context.dispatch(storeActions.RESET_DAMAGE_STATE_AND_DEPENDENCIES);
|
||||||
context.dispatch(storeActions.RESET_PARTS_STATE_AND_DEPENDENCIES);
|
context.dispatch(storeActions.RESET_PARTS_STATE_AND_DEPENDENCIES);
|
||||||
|
|
@ -1107,12 +1305,11 @@ export const actions = {
|
||||||
},
|
},
|
||||||
clearVin(context) {
|
clearVin(context) {
|
||||||
context.commit(storeMutations.UPDATE_VEHICLE_VIN, null);
|
context.commit(storeMutations.UPDATE_VEHICLE_VIN, null);
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
|
|
||||||
export default createStore({
|
export default createStore({
|
||||||
plugins: [createPersistedState()],
|
plugins: [createPersistedState()],
|
||||||
|
|
||||||
// IMPORTANT: Be VERY careful when modifying these fields for at least a few reasons:
|
// IMPORTANT: Be VERY careful when modifying these fields for at least a few reasons:
|
||||||
// * The CMS can reference the fields by name
|
// * The CMS can reference the fields by name
|
||||||
// * Return users may have a previous "version" of the model, and we don't want
|
// * Return users may have a previous "version" of the model, and we don't want
|
||||||
|
|
@ -1126,30 +1323,27 @@ export default createStore({
|
||||||
// Private Functions
|
// Private Functions
|
||||||
|
|
||||||
function getHasRecalibrationPart(state) {
|
function getHasRecalibrationPart(state) {
|
||||||
var hasRequiresRecalibration = getAllValuesOfPropertyInArrayOfObjects(state.order.lineItems.glassParts, "requiresRecalibration")?.length > 0;
|
var hasRequiresRecalibration = getNonFalseValuesOfPropertyInArrayOfObjects(state.order.lineItems.glassParts, "requiresRecalibration")?.length > 0;
|
||||||
var hasRecalibrationType = getAllValuesOfPropertyInArrayOfObjects(state.order.lineItems.glassParts, "recalibrationType")?.length > 0;
|
var hasRecalibrationType = getNonFalseValuesOfPropertyInArrayOfObjects(state.order.lineItems.glassParts, "recalibrationType")?.length > 0;
|
||||||
|
|
||||||
if (hasRequiresRecalibration) {
|
if (hasRequiresRecalibration) {
|
||||||
if (hasRecalibrationType) { // Has both 'requiresRecalibration' and 'recalibrationType' and 'recalibrationType'
|
if (hasRecalibrationType) { // Has both 'requiresRecalibration' and 'recalibrationType' and 'recalibrationType'
|
||||||
return getAllValuesOfPropertyInArrayOfObjects(state.order.lineItems.glassParts, "recalibrationType")[0].toLowerCase() != "unknown";
|
return getNonFalseValuesOfPropertyInArrayOfObjects(state.order.lineItems.glassParts, "recalibrationType")[0].toLowerCase() != "unknown";
|
||||||
} else { // Has 'requiresRecalibration' but no 'recalibrationType' at all
|
} else { // Has 'requiresRecalibration' but no 'recalibrationType' at all
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else { // Does not have 'requiresRecalibration'
|
} else {
|
||||||
|
// Does not have 'requiresRecalibration'
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function sortArrayOfObjectsByPropertyValue(arrayOfObjects, propertyName) {
|
function sortArrayOfObjectsByPropertyValue(arrayOfObjects, propertyName) {
|
||||||
if (!arrayOfObjects) return null;
|
if (!arrayOfObjects) return null;
|
||||||
|
|
||||||
return arrayOfObjects.sort((a, b) => {
|
return arrayOfObjects.sort((a, b) => {
|
||||||
if (a[propertyName] < b[propertyName])
|
if (a[propertyName] < b[propertyName]) return -1;
|
||||||
return -1;
|
else if (a[propertyName] > b[propertyName]) return 1;
|
||||||
else if (a[propertyName] > b[propertyName])
|
else return 0;
|
||||||
return 1;
|
});
|
||||||
else
|
|
||||||
return 0;
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
@ -2,15 +2,17 @@
|
||||||
<button
|
<button
|
||||||
:aria-disabled="isDisabled"
|
:aria-disabled="isDisabled"
|
||||||
class="btn d-flex align-items-center py-3 px-4 delay"
|
class="btn d-flex align-items-center py-3 px-4 delay"
|
||||||
:class="[isPrimary ? 'btn-primary' : 'btn-secondary',isFloat ? 'float-end' : '', isLoaderDisplayed ? 'has-loader' : '']"
|
:class="[
|
||||||
@click="clicked"
|
isPrimary ? 'btn-primary' : 'btn-secondary',
|
||||||
>
|
isFloat ? 'float-end' : '',
|
||||||
|
isLoaderDisplayed ? 'has-loader' : '',
|
||||||
|
]"
|
||||||
|
@click="clicked">
|
||||||
<span class="m-0">{{ this.buttonText }}</span>
|
<span class="m-0">{{ this.buttonText }}</span>
|
||||||
<loader
|
<loader
|
||||||
class="ms-2"
|
class="ms-2"
|
||||||
v-if="isLoaderDisplayed"
|
v-if="isLoaderDisplayed"
|
||||||
v-bind:class="[this.loaderColor, this.loaderPosition]"
|
v-bind:class="[this.loaderColor, this.loaderPosition]" />
|
||||||
/>
|
|
||||||
</button>
|
</button>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
@ -33,11 +35,16 @@ export default {
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
removeLoader(){
|
removeLoader() {
|
||||||
this.isLoaderDisplayed = false;
|
this.isLoaderDisplayed = false;
|
||||||
},
|
},
|
||||||
clicked() {
|
clicked() {
|
||||||
this.pushEventToGA(this.$route.query[this.queryStrings.FMG_PAGE], this.GaActions.CLICKED, this.buttonText, true);
|
this.pushEventToGA(
|
||||||
|
this.$route.query[this.queryStrings.FMG_PAGE],
|
||||||
|
this.GaActions.CLICKED,
|
||||||
|
this.buttonText,
|
||||||
|
true
|
||||||
|
);
|
||||||
if (!this.isDisabled) {
|
if (!this.isDisabled) {
|
||||||
this.isLoaderDisplayed = true;
|
this.isLoaderDisplayed = true;
|
||||||
this.$emit("click-event");
|
this.$emit("click-event");
|
||||||
|
|
@ -98,7 +105,8 @@ export default {
|
||||||
background: $blue-700;
|
background: $blue-700;
|
||||||
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;
|
||||||
}
|
}
|
||||||
&.delay {// fixes flicker while transitioning between states
|
&.delay {
|
||||||
|
// fixes flicker while transitioning between states
|
||||||
transition: background 0s 0s ease-in-out;
|
transition: background 0s 0s ease-in-out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -137,7 +145,8 @@ export default {
|
||||||
color: $white;
|
color: $white;
|
||||||
@include blue-gradient;
|
@include blue-gradient;
|
||||||
}
|
}
|
||||||
&.delay {// fixes flicker while transitioning between states
|
&.delay {
|
||||||
|
// fixes flicker while transitioning between states
|
||||||
transition: background 0s 0s ease-in-out;
|
transition: background 0s 0s ease-in-out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,272 +1,201 @@
|
||||||
import { shallowMount } from "@vue/test-utils";
|
import { shallowMount, mount } from "@vue/test-utils";
|
||||||
import listButtonHorizontal from "./list-button-horizontal";
|
import listButtonHorizontal from "./list-button-horizontal";
|
||||||
import { nextTick } from "vue";
|
import { nextTick } from "vue";
|
||||||
import { GaActions } from "@/constants/analytics";
|
import { GaActions } from "@/constants/analytics";
|
||||||
|
import inputButtonWrapperMixin from "@/mixins/input-button-wrapper-mixin";
|
||||||
|
|
||||||
// TODO KO
|
describe("list-button-horizontal.vue", () => {
|
||||||
describe.skip("list-button-horizontal.vue", () => {
|
// TODO KO Have this moved out to somewhere shared
|
||||||
it("Should return input type checkbox if isMultiSelect is true", async () => {
|
describe("Shared baseInputButton checks", () => {
|
||||||
// Act
|
it("Should return input type checkbox if isMultiSelect is true", async () => {
|
||||||
const wrapper = shallowMount(listButtonHorizontal, {
|
// Act
|
||||||
propsData: {
|
const { wrapper } = setupMocks({
|
||||||
isMultiSelect: true,
|
mockData: {
|
||||||
},
|
propsData: {
|
||||||
|
isMultiSelect: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
const input = wrapper.find("input");
|
||||||
|
expect(input.attributes().type).toEqual("checkbox");
|
||||||
});
|
});
|
||||||
|
|
||||||
// Assert
|
it("Should return input type radio if isMultiSelect is false or not specified", async () => {
|
||||||
const input = wrapper.find("input");
|
// Act
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
mockData: {
|
||||||
|
propsData: {
|
||||||
|
isMultiSelect: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
expect(input.attributes().type).toEqual("checkbox");
|
// Assert
|
||||||
});
|
const input = wrapper.find("input");
|
||||||
|
expect(input.attributes().type).toEqual("radio");
|
||||||
it("Should return input type radio if isMultiSelect is false or not specified", async () => {
|
|
||||||
// Act
|
|
||||||
const wrapper = shallowMount(listButtonHorizontal, {
|
|
||||||
propsData: {
|
|
||||||
isMultiSelect: false,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Assert
|
it("Should emit button value on click", async () => {
|
||||||
const input = wrapper.find("input");
|
// 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",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
expect(input.attributes().type).toEqual("radio");
|
// Act
|
||||||
|
wrapper.vm.handleAnswerChange("test");
|
||||||
|
await wrapper.vm.$nextTick();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(wrapper.emitted()["change"][0]).toEqual(["test"]);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should return primary label text (buttonID)", async () => {
|
describe("styling/UI", () => {
|
||||||
// Act
|
it("Should return screen reader text", async () => {
|
||||||
const wrapper = shallowMount(listButtonHorizontal, {
|
// Act
|
||||||
propsData: {
|
const { wrapper } = setupMocks({
|
||||||
buttonID: "List Card Checkbox",
|
mockData: {
|
||||||
},
|
propsData: {
|
||||||
|
screenReaderOnlyText: "Screen Reader Only Text",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
const paragraph = wrapper.find("span.sr-only");
|
||||||
|
|
||||||
|
expect(paragraph.text()).toEqual("Screen Reader Only Text");
|
||||||
});
|
});
|
||||||
|
|
||||||
// Assert
|
it("Should return text alignment class", async () => {
|
||||||
const label = wrapper.find("label");
|
// Act
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
mockData: {
|
||||||
|
propsData: {
|
||||||
|
textPosition: "text-center",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
expect(label.attributes().for).toEqual("List Card Checkbox");
|
// Assert
|
||||||
});
|
const paragraph = wrapper.find("span.m-0");
|
||||||
|
|
||||||
it("Should return screen reader text", async () => {
|
expect(paragraph.attributes("class")).toContain("text-center");
|
||||||
// Act
|
|
||||||
const wrapper = shallowMount(listButtonHorizontal, {
|
|
||||||
propsData: {
|
|
||||||
screenReaderOnlyText: "Screen Reader Only Text",
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Assert
|
it("Should return aria-required state", async () => {
|
||||||
const paragraph = wrapper.find("span.sr-only");
|
// Act
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
mockData: {
|
||||||
|
propsData: {
|
||||||
|
isRequired: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
expect(paragraph.text()).toEqual("Screen Reader Only Text");
|
// Assert
|
||||||
});
|
const input = wrapper.find("input");
|
||||||
|
|
||||||
it("Should return text alignment class", async () => {
|
expect(input.attributes()["aria-required"]).toEqual("true");
|
||||||
// Act
|
|
||||||
const wrapper = shallowMount(listButtonHorizontal, {
|
|
||||||
propsData: {
|
|
||||||
textPosition: "text-center",
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Assert
|
it("is cash or insurance button => has 'radio-fancy' class", () => {
|
||||||
const paragraph = wrapper.find("span.m-0");
|
// Arrange/Act
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
mockData: {
|
||||||
|
propsData: {
|
||||||
|
isCashOrInsurance: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
expect(paragraph.attributes("class")).toContain("text-center");
|
// Assert
|
||||||
});
|
const label = wrapper.find("label");
|
||||||
|
|
||||||
it("Should return aria-required state", async () => {
|
expect(label.classes()).toContain("radio-fancy");
|
||||||
// Act
|
|
||||||
const wrapper = shallowMount(listButtonHorizontal, {
|
|
||||||
propsData: {
|
|
||||||
isRequired: true,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Assert
|
test("has buttonLabel => displays buttonLabel", () => {
|
||||||
const input = wrapper.find("input");
|
// Arrange/Act
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
mockData: {
|
||||||
|
propsData: {
|
||||||
|
buttonLabel: "Surprise!",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
expect(input.attributes()["aria-required"]).toEqual("true");
|
// Assert
|
||||||
});
|
const content = wrapper.find(".list-button-horizontal-content");
|
||||||
|
expect(content.isVisible()).toBe(true);
|
||||||
it("Should return loader enabled true", async () => {
|
expect(content.text()).toContain("Surprise!");
|
||||||
// Act
|
|
||||||
const wrapper = shallowMount(listButtonHorizontal, {
|
|
||||||
global: {
|
|
||||||
mocks: {
|
|
||||||
'$route': { query: { fmgPage: 'page-name' } },
|
|
||||||
GaActions: GaActions,
|
|
||||||
pushEventToGA: jest.fn(),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
propsData: {
|
|
||||||
selectingInitiatesLoad: true,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Assert
|
test("has buttonLabelSubCopy => displays buttonLabelSubCopy", () => {
|
||||||
|
// Arrange/Act
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
mockData: {
|
||||||
|
propsData: {
|
||||||
|
buttonLabel: "Surprise!",
|
||||||
|
buttonLabelSubCopy: "Super duper surprise :)",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
const label = wrapper.find("label");
|
// Assert
|
||||||
|
const content = wrapper.find(".list-button-horizontal-content");
|
||||||
wrapper.vm.handleCheckChange = jest.fn();
|
expect(content.isVisible()).toBe(true);
|
||||||
wrapper.vm.triggerButton();
|
expect(content.text()).toContain("Super duper surprise :)");
|
||||||
|
|
||||||
await nextTick();
|
|
||||||
|
|
||||||
const loader = wrapper.find("loader-stub");
|
|
||||||
|
|
||||||
expect(loader.exists()).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Should return loader color", async () => {
|
|
||||||
// Act
|
|
||||||
const wrapper = shallowMount(listButtonHorizontal, {
|
|
||||||
global: {
|
|
||||||
mocks: {
|
|
||||||
'$route': { query: { fmgPage: 'page-name' } },
|
|
||||||
GaActions: GaActions,
|
|
||||||
pushEventToGA: jest.fn(),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
propsData: {
|
|
||||||
loaderColor: "blue",
|
|
||||||
selectingInitiatesLoad: true,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Assert
|
test("has screenReaderOnlyText => displays screenReaderOnlyText", () => {
|
||||||
|
// Arrange/Act
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
mockData: {
|
||||||
|
propsData: {
|
||||||
|
buttonLabel: "Surprise!",
|
||||||
|
buttonLabelSubCopy: "Super duper surprise :)",
|
||||||
|
screenReaderOnlyText: "Tests are fun!"
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
const label = wrapper.find("label");
|
// Assert
|
||||||
|
const content = wrapper.find(".list-button-horizontal-content");
|
||||||
wrapper.vm.handleCheckChange = jest.fn();
|
const screenReaderOnlyText = wrapper.find(".sr-only");
|
||||||
wrapper.vm.triggerButton();
|
expect(content.isVisible()).toBe(true);
|
||||||
|
expect(screenReaderOnlyText.exists()).toBe(true);
|
||||||
await nextTick();
|
expect(screenReaderOnlyText.text()).toContain("Tests are fun!");
|
||||||
|
|
||||||
const loader = wrapper.find("loader-stub");
|
|
||||||
|
|
||||||
expect(loader.attributes("class")).toContain("blue");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Should return loader position", async () => {
|
|
||||||
// Act
|
|
||||||
const wrapper = shallowMount(listButtonHorizontal, {
|
|
||||||
global: {
|
|
||||||
mocks: {
|
|
||||||
'$route': { query: { fmgPage: 'page-name' } },
|
|
||||||
GaActions: GaActions,
|
|
||||||
pushEventToGA: jest.fn(),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
propsData: {
|
|
||||||
loaderPosition: "right",
|
|
||||||
selectingInitiatesLoad: true,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Assert
|
|
||||||
|
|
||||||
const label = wrapper.find("label");
|
|
||||||
|
|
||||||
wrapper.vm.handleCheckChange = jest.fn();
|
|
||||||
wrapper.vm.triggerButton();
|
|
||||||
|
|
||||||
await nextTick();
|
|
||||||
|
|
||||||
const loader = wrapper.find("loader-stub");
|
|
||||||
|
|
||||||
expect(loader.attributes("class")).toContain("right");
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should emit button value on click", async () => {
|
|
||||||
// Act
|
|
||||||
const wrapper = shallowMount(listButtonHorizontal, {
|
|
||||||
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"],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
wrapper.vm.handleCheckChange();
|
|
||||||
// Assert
|
|
||||||
expect(wrapper.emitted()["isCheckedChanged"][0]).toEqual([{value: "List Card Checkbox", checkValue: Boolean, buttonId: undefined, checkValue: false}]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Should set checkValue data if selectedButtonIDs has value(s)", async () => {
|
|
||||||
// Act
|
|
||||||
const wrapper = shallowMount(listButtonHorizontal, {
|
|
||||||
propsData: {
|
|
||||||
isRadioHorizontal: true,
|
|
||||||
buttonLabel: "Windshield",
|
|
||||||
buttonID: "List Card Checkbox",
|
|
||||||
groupID: "radio-demo-1",
|
|
||||||
groupName: "radio 1",
|
|
||||||
buttonImage: "windshield-damage.svg",
|
|
||||||
isRequired: true,
|
|
||||||
isWide: false,
|
|
||||||
modelValue: ["List Card Checkbox"],
|
|
||||||
isMultiSelect: false,
|
|
||||||
value: "Car-Front",
|
|
||||||
selectedValues: ["Car-Front"]
|
|
||||||
},
|
|
||||||
});
|
|
||||||
// Assert
|
|
||||||
expect(wrapper.vm.checkValue).toEqual(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Should run handleCheckChange if selectingInitiatesLoad is false and handleInputChange is triggered", async () => {
|
|
||||||
// Act
|
|
||||||
const wrapper = shallowMount(listButtonHorizontal, {
|
|
||||||
propsData: {
|
|
||||||
selectingInitiatesLoad: false,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
wrapper.vm.handleInputChange();
|
|
||||||
|
|
||||||
await nextTick();
|
|
||||||
|
|
||||||
expect(wrapper.vm.handleCheckChange).toBeCalled;
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Should do nothing if isMultiSelect is true and handleKeyupArrow is triggered", async () => {
|
|
||||||
// Act
|
|
||||||
const wrapper = shallowMount(listButtonHorizontal, {
|
|
||||||
propsData: {
|
|
||||||
isMultiSelect: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
wrapper.vm.handleKeyupArrow();
|
|
||||||
|
|
||||||
await nextTick();
|
|
||||||
|
|
||||||
expect(wrapper.vm.handleKeyupArrow).toHaveReturned;
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Should run handleCheckChange if selectingInitiatesLoad is false and handleKeyupArrow is triggered", async () => {
|
|
||||||
// Act
|
|
||||||
const wrapper = shallowMount(listButtonHorizontal, {
|
|
||||||
propsData: {
|
|
||||||
selectingInitiatesLoad: false,
|
|
||||||
isMultiSelect: false,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
wrapper.vm.handleKeyupArrow();
|
|
||||||
|
|
||||||
await nextTick();
|
|
||||||
|
|
||||||
expect(wrapper.vm.handleCheckChange).toBeCalled;
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function setupMocks({ mockData }) {
|
||||||
|
const wrapper = mount(listButtonHorizontal, {
|
||||||
|
...mockData,
|
||||||
|
propsData: {
|
||||||
|
...mockData.propsData,
|
||||||
|
groupName: "my-group",
|
||||||
|
modelValue: mockData.propsData?.isMultiSelect ? ["5"] : "5",
|
||||||
|
value: mockData.propsData?.isMultiSelect ? ["4"] : "4"
|
||||||
|
},
|
||||||
|
mixins: [inputButtonWrapperMixin],
|
||||||
|
});
|
||||||
|
|
||||||
|
return { wrapper };
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
'list-group list-button-horizontal d-flex flex-column w-100',
|
'list-group list-button-horizontal d-flex flex-column w-100',
|
||||||
{ 'radio-fancy': isCashOrInsurance },
|
{ 'radio-fancy': isCashOrInsurance },
|
||||||
]"
|
]"
|
||||||
@buttonClicked="handleAnswerChange">
|
@inputButtonClicked="handleAnswerChange">
|
||||||
<div
|
<div
|
||||||
class="list-button-horizontal-content d-flex flex-column justify-content-center p-3">
|
class="list-button-horizontal-content d-flex flex-column justify-content-center p-3">
|
||||||
<span class="m-0" :class="textPosition">
|
<span class="m-0" :class="textPosition">
|
||||||
|
|
|
||||||
|
|
@ -1,264 +1,261 @@
|
||||||
import { shallowMount } from "@vue/test-utils";
|
import { shallowMount, mount } from "@vue/test-utils";
|
||||||
import listButton from "./list-button";
|
import listButton from "./list-button";
|
||||||
import { nextTick } from "vue";
|
import { nextTick } from "vue";
|
||||||
import { GaActions } from "@/constants/analytics";
|
import { GaActions } from "@/constants/analytics";
|
||||||
|
import inputButtonWrapperMixin from "@/mixins/input-button-wrapper-mixin";
|
||||||
|
|
||||||
// TODO KO
|
describe("list-button.vue", () => {
|
||||||
describe.skip("list-button.vue", () => {
|
describe("loader", () => {
|
||||||
it("Should return input type checkbox if isMultiSelect is true", async () => {
|
it("selectingInitiatesLoad is true and answer is changed => show the loader", async () => {
|
||||||
// Act
|
// Act
|
||||||
const wrapper = shallowMount(listButton, {
|
const { wrapper } = setupMocks({
|
||||||
propsData: {
|
mockData: {
|
||||||
isMultiSelect: true,
|
global: {
|
||||||
},
|
mocks: {
|
||||||
|
$route: { query: { fmgPage: "page-name" } },
|
||||||
|
GaActions: GaActions,
|
||||||
|
pushEventToGA: jest.fn(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
propsData: {
|
||||||
|
selectingInitiatesLoad: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
wrapper.vm.handleAnswerChange("something");
|
||||||
|
await wrapper.vm.$nextTick();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
const loader = wrapper.findComponent({ name: "loader" });
|
||||||
|
expect(loader.exists()).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Assert
|
it("Should return loader color", async () => {
|
||||||
const input = wrapper.find("input");
|
// Act
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
mockData: {
|
||||||
|
global: {
|
||||||
|
mocks: {
|
||||||
|
$route: { query: { fmgPage: "page-name" } },
|
||||||
|
GaActions: GaActions,
|
||||||
|
pushEventToGA: jest.fn(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
propsData: {
|
||||||
|
loaderColor: "blue",
|
||||||
|
selectingInitiatesLoad: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
expect(input.attributes().type).toEqual("checkbox");
|
// Act
|
||||||
});
|
wrapper.vm.handleAnswerChange("something");
|
||||||
|
await nextTick();
|
||||||
|
|
||||||
it("Should return input type radio if isMultiSelect is false or not specified", async () => {
|
// Assert
|
||||||
// Act
|
const loader = wrapper.findComponent({ name: "loader" });
|
||||||
const wrapper = shallowMount(listButton, {
|
expect(loader.attributes("class")).toContain("blue");
|
||||||
propsData: {
|
|
||||||
isMultiSelect: false,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Assert
|
it("Should return loader position", async () => {
|
||||||
const input = wrapper.find("input");
|
// Act
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
mockData: {
|
||||||
|
global: {
|
||||||
|
mocks: {
|
||||||
|
$route: { query: { fmgPage: "page-name" } },
|
||||||
|
GaActions: GaActions,
|
||||||
|
pushEventToGA: jest.fn(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
propsData: {
|
||||||
|
loaderPosition: "right",
|
||||||
|
selectingInitiatesLoad: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
expect(input.attributes().type).toEqual("radio");
|
// Act
|
||||||
|
wrapper.vm.handleAnswerChange("test");
|
||||||
|
await nextTick();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
const loader = wrapper.findComponent({ name: "loader" });
|
||||||
|
expect(loader.attributes("class")).toContain("right");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should return primary label text (buttonID)", async () => {
|
describe("baseInputButton checks", () => {
|
||||||
// Act
|
it("Should return input type checkbox if isMultiSelect is true", async () => {
|
||||||
const wrapper = shallowMount(listButton, {
|
// Act
|
||||||
propsData: {
|
const { wrapper } = setupMocks({
|
||||||
buttonID: "List Card Checkbox",
|
mockData: {
|
||||||
},
|
propsData: {
|
||||||
|
isMultiSelect: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
const input = wrapper.find("input");
|
||||||
|
|
||||||
|
expect(input.attributes().type).toEqual("checkbox");
|
||||||
});
|
});
|
||||||
|
|
||||||
// Assert
|
it("Should return input type radio if isMultiSelect is false or not specified", async () => {
|
||||||
const label = wrapper.find("label");
|
// Act
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
mockData: {
|
||||||
|
propsData: {
|
||||||
|
isMultiSelect: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
expect(label.attributes().for).toEqual("List Card Checkbox");
|
// Assert
|
||||||
});
|
const input = wrapper.find("input");
|
||||||
|
expect(input.attributes().type).toEqual("radio");
|
||||||
it("Should return screen reader text", async () => {
|
|
||||||
// Act
|
|
||||||
const wrapper = shallowMount(listButton, {
|
|
||||||
propsData: {
|
|
||||||
screenReaderOnlyText: "Screen Reader Only Text",
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Assert
|
it("Should emit button value on click", async () => {
|
||||||
const paragraph = wrapper.find("span.sr-only");
|
// 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",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
expect(paragraph.text()).toEqual("Screen Reader Only Text");
|
// Act
|
||||||
|
wrapper.vm.handleAnswerChange("test");
|
||||||
|
await wrapper.vm.$nextTick();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(wrapper.emitted()["change"][0]).toEqual(["test"]);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should return text alignment class", async () => {
|
describe("styling/UI", () => {
|
||||||
// Act
|
test("has buttonLabel => displays buttonLabel", () => {
|
||||||
const wrapper = shallowMount(listButton, {
|
// Arrange/Act
|
||||||
propsData: {
|
const { wrapper } = setupMocks({
|
||||||
textPosition: "text-center",
|
mockData: {
|
||||||
},
|
propsData: {
|
||||||
|
buttonLabel: "Surprise!",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
const content = wrapper.find(".list-button-content");
|
||||||
|
expect(content.isVisible()).toBe(true);
|
||||||
|
expect(content.text()).toContain("Surprise!");
|
||||||
});
|
});
|
||||||
|
|
||||||
// Assert
|
test("has buttonLabelSubCopy => displays buttonLabelSubCopy", () => {
|
||||||
const paragraph = wrapper.find("span.m-0");
|
// Arrange/Act
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
mockData: {
|
||||||
|
propsData: {
|
||||||
|
buttonLabel: "Surprise!",
|
||||||
|
buttonLabelSubCopy: "Super duper surprise :)",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
expect(paragraph.attributes("class")).toContain("text-center");
|
// Assert
|
||||||
});
|
const content = wrapper.find(".list-button-content");
|
||||||
|
expect(content.isVisible()).toBe(true);
|
||||||
it("Should return aria-required state", async () => {
|
expect(content.text()).toContain("Super duper surprise :)");
|
||||||
// Act
|
|
||||||
const wrapper = shallowMount(listButton, {
|
|
||||||
propsData: {
|
|
||||||
isRequired: true,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Assert
|
test("has screenReaderOnlyText => displays screenReaderOnlyText", () => {
|
||||||
const input = wrapper.find("input");
|
// Arrange/Act
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
mockData: {
|
||||||
|
propsData: {
|
||||||
|
buttonLabel: "Surprise!",
|
||||||
|
buttonLabelSubCopy: "Super duper surprise :)",
|
||||||
|
screenReaderOnlyText: "Tests are fun!",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
expect(input.attributes()["aria-required"]).toEqual("true");
|
// Assert
|
||||||
});
|
const content = wrapper.find(".list-button-content");
|
||||||
|
const screenReaderOnlyText = wrapper.find(".sr-only");
|
||||||
it("Should return loader enabled true", async () => {
|
expect(content.isVisible()).toBe(true);
|
||||||
// Act
|
expect(screenReaderOnlyText.exists()).toBe(true);
|
||||||
const wrapper = shallowMount(listButton, {
|
expect(screenReaderOnlyText.text()).toContain("Tests are fun!");
|
||||||
global: {
|
|
||||||
mocks: {
|
|
||||||
'$route': { query: { fmgPage: 'page-name' } },
|
|
||||||
GaActions: GaActions,
|
|
||||||
pushEventToGA: jest.fn(),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
propsData: {
|
|
||||||
selectingInitiatesLoad: true,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Assert
|
it("Should return screen reader text", async () => {
|
||||||
wrapper.vm.handleCheckChange = jest.fn();
|
// Act
|
||||||
wrapper.vm.triggerButton();
|
const { wrapper } = setupMocks({
|
||||||
|
mockData: {
|
||||||
|
propsData: {
|
||||||
|
screenReaderOnlyText: "Screen Reader Only Text",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
await nextTick();
|
// Assert
|
||||||
|
const paragraph = wrapper.find("span.sr-only");
|
||||||
|
|
||||||
const loader = wrapper.find("loader-stub");
|
expect(paragraph.text()).toEqual("Screen Reader Only Text");
|
||||||
|
|
||||||
expect(loader.exists()).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Should return loader color", async () => {
|
|
||||||
// Act
|
|
||||||
const wrapper = shallowMount(listButton, {
|
|
||||||
global: {
|
|
||||||
mocks: {
|
|
||||||
'$route': { query: { fmgPage: 'page-name' } },
|
|
||||||
GaActions: GaActions,
|
|
||||||
pushEventToGA: jest.fn(),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
propsData: {
|
|
||||||
loaderColor: "blue",
|
|
||||||
selectingInitiatesLoad: true,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Assert
|
it("Should return text alignment class", async () => {
|
||||||
wrapper.vm.handleCheckChange = jest.fn();
|
// Act
|
||||||
wrapper.vm.triggerButton();
|
const { wrapper } = setupMocks({
|
||||||
await nextTick();
|
mockData: {
|
||||||
|
propsData: {
|
||||||
|
textPosition: "text-center",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
const loader = wrapper.find("loader-stub");
|
// Assert
|
||||||
|
const paragraph = wrapper.find("span.m-0");
|
||||||
|
|
||||||
expect(loader.attributes("class")).toContain("blue");
|
expect(paragraph.attributes("class")).toContain("text-center");
|
||||||
});
|
|
||||||
|
|
||||||
it("Should return loader position", async () => {
|
|
||||||
// Act
|
|
||||||
const wrapper = shallowMount(listButton, {
|
|
||||||
global: {
|
|
||||||
mocks: {
|
|
||||||
'$route': { query: { fmgPage: 'page-name' } },
|
|
||||||
GaActions: GaActions,
|
|
||||||
pushEventToGA: jest.fn(),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
propsData: {
|
|
||||||
loaderPosition: "right",
|
|
||||||
selectingInitiatesLoad: true,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Assert
|
it("Should return aria-required state", async () => {
|
||||||
wrapper.vm.handleCheckChange = jest.fn();
|
// Act
|
||||||
wrapper.vm.triggerButton();
|
const { wrapper } = setupMocks({
|
||||||
|
mockData: {
|
||||||
|
propsData: {
|
||||||
|
isRequired: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
await nextTick();
|
// Assert
|
||||||
|
const input = wrapper.find("input");
|
||||||
|
|
||||||
const loader = wrapper.find("loader-stub");
|
expect(input.attributes()["aria-required"]).toEqual("true");
|
||||||
|
|
||||||
expect(loader.attributes("class")).toContain("right");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Should emit button value on click", async () => {
|
|
||||||
// Act
|
|
||||||
const wrapper = shallowMount(listButton, {
|
|
||||||
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'
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
wrapper.vm.handleCheckChange();
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
expect(wrapper.emitted()["isCheckedChanged"][0]).toEqual([{value: "List Card Checkbox", checkValue: false, buttonId: 'list-card-id'}]);
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should set checkValue data if selectedButtonIDs has value(s)", async () => {
|
|
||||||
// Act
|
|
||||||
const wrapper = shallowMount(listButton, {
|
|
||||||
propsData: {
|
|
||||||
isRadioHorizontal: true,
|
|
||||||
buttonLabel: "Windshield",
|
|
||||||
buttonID: "List Card Checkbox",
|
|
||||||
groupID: "radio-demo-1",
|
|
||||||
groupName: "radio 1",
|
|
||||||
buttonImage: "windshield-damage.svg",
|
|
||||||
isRequired: true,
|
|
||||||
isWide: false,
|
|
||||||
modelValue: ["List Card Checkbox"],
|
|
||||||
selectedValues: "Car-Front"
|
|
||||||
},
|
|
||||||
});
|
|
||||||
// Assert
|
|
||||||
expect(wrapper.componentVM.checkValue).toEqual(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Should run handleCheckChange if selectingInitiatesLoad is false and handleInputChange is triggered", async () => {
|
|
||||||
// Act
|
|
||||||
const wrapper = shallowMount(listButton, {
|
|
||||||
propsData: {
|
|
||||||
selectingInitiatesLoad: false,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
wrapper.vm.handleInputChange();
|
|
||||||
|
|
||||||
await nextTick();
|
|
||||||
|
|
||||||
expect(wrapper.vm.handleCheckChange).toBeCalled;
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Should do nothing if isMultiSelect is true and handleKeyupArrow is triggered", async () => {
|
|
||||||
// Act
|
|
||||||
const wrapper = shallowMount(listButton, {
|
|
||||||
propsData: {
|
|
||||||
isMultiSelect: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
wrapper.vm.handleKeyupArrow();
|
|
||||||
|
|
||||||
await nextTick();
|
|
||||||
|
|
||||||
expect(wrapper.vm.handleKeyupArrow).toHaveReturned;
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Should run handleCheckChange if selectingInitiatesLoad is false and handleKeyupArrow is triggered", async () => {
|
|
||||||
// Act
|
|
||||||
const wrapper = shallowMount(listButton, {
|
|
||||||
propsData: {
|
|
||||||
selectingInitiatesLoad: false,
|
|
||||||
isMultiSelect: false,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
wrapper.vm.handleKeyupArrow();
|
|
||||||
|
|
||||||
await nextTick();
|
|
||||||
|
|
||||||
expect(wrapper.vm.handleCheckChange).toBeCalled;
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function setupMocks({ mockData }) {
|
||||||
|
const wrapper = mount(listButton, {
|
||||||
|
...mockData,
|
||||||
|
mixins: [inputButtonWrapperMixin],
|
||||||
|
});
|
||||||
|
|
||||||
|
return { wrapper };
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
<baseInputButton
|
<baseInputButton
|
||||||
v-bind="$props"
|
v-bind="$props"
|
||||||
buttonWrapperClasses="list-group list-button rounded-3 d-flex flex-column w-100 mb-2"
|
buttonWrapperClasses="list-group list-button rounded-3 d-flex flex-column w-100 mb-2"
|
||||||
@buttonClicked="handleAnswerChange">
|
@inputButtonClicked="handleAnswerChange">
|
||||||
<div
|
<div
|
||||||
:aria-label="buttonLabel"
|
:aria-label="buttonLabel"
|
||||||
class="list-button-content d-flex flex-column justify-content-center py-3 px-4">
|
class="list-button-content d-flex flex-column justify-content-center py-3 px-4">
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ describe("list-card.vue", () => {
|
||||||
groupID: "checkbox-demo-1",
|
groupID: "checkbox-demo-1",
|
||||||
groupName: "Checkbox 1",
|
groupName: "Checkbox 1",
|
||||||
buttonImage: "windshield-damage.svg",
|
buttonImage: "windshield-damage.svg",
|
||||||
|
value: "test value",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -32,6 +33,7 @@ describe("list-card.vue", () => {
|
||||||
groupID: "radio-demo-1",
|
groupID: "radio-demo-1",
|
||||||
groupName: "radio 1",
|
groupName: "radio 1",
|
||||||
buttonImage: "windshield-damage.svg",
|
buttonImage: "windshield-damage.svg",
|
||||||
|
value: "test value",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -51,6 +53,7 @@ describe("list-card.vue", () => {
|
||||||
groupName: "radio 1",
|
groupName: "radio 1",
|
||||||
buttonImage: "windshield-damage.svg",
|
buttonImage: "windshield-damage.svg",
|
||||||
buttonLabelSubCopy: "Test",
|
buttonLabelSubCopy: "Test",
|
||||||
|
value: "test value",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -70,6 +73,7 @@ describe("list-card.vue", () => {
|
||||||
groupName: "radio 1",
|
groupName: "radio 1",
|
||||||
buttonImage: "windshield-damage.svg",
|
buttonImage: "windshield-damage.svg",
|
||||||
buttonLabelSubCopy: "Test",
|
buttonLabelSubCopy: "Test",
|
||||||
|
value: "test value",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -89,6 +93,7 @@ describe("list-card.vue", () => {
|
||||||
groupName: "radio 1",
|
groupName: "radio 1",
|
||||||
buttonImage: "windshield-damage.svg",
|
buttonImage: "windshield-damage.svg",
|
||||||
isRequired: true,
|
isRequired: true,
|
||||||
|
value: "test value",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -110,6 +115,7 @@ describe("list-card.vue", () => {
|
||||||
isRequired: true,
|
isRequired: true,
|
||||||
isWide: true,
|
isWide: true,
|
||||||
buttonLabelSubCopy: "",
|
buttonLabelSubCopy: "",
|
||||||
|
value: "test value",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -134,6 +140,7 @@ describe("list-card.vue", () => {
|
||||||
isRequired: true,
|
isRequired: true,
|
||||||
isWide: true,
|
isWide: true,
|
||||||
buttonLabelSubCopy: "Button Subcopy",
|
buttonLabelSubCopy: "Button Subcopy",
|
||||||
|
value: "test value",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -159,6 +166,7 @@ describe("list-card.vue", () => {
|
||||||
buttonImage: "windshield-damage.svg",
|
buttonImage: "windshield-damage.svg",
|
||||||
isRequired: true,
|
isRequired: true,
|
||||||
isWide: false,
|
isWide: false,
|
||||||
|
value: "test value",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
'list-card w-100 rounded-3 d-flex align-items-center h-100',
|
'list-card w-100 rounded-3 d-flex align-items-center h-100',
|
||||||
{ horizontal: isWide },
|
{ horizontal: isWide },
|
||||||
]"
|
]"
|
||||||
@buttonClicked="handleAnswerChange">
|
@inputButtonClicked="handleAnswerChange">
|
||||||
<div
|
<div
|
||||||
class="d-flex w-100 align-items-center px-2 h-100 list-card-content"
|
class="d-flex w-100 align-items-center px-2 h-100 list-card-content"
|
||||||
:class="labelClasses">
|
:class="labelClasses">
|
||||||
|
|
|
||||||
|
|
@ -6,12 +6,16 @@ import inputButtonWrapperMixin from "@/mixins/input-button-wrapper-mixin";
|
||||||
describe("radio.vue", () => {
|
describe("radio.vue", () => {
|
||||||
it("Should have correct group name", async () => {
|
it("Should have correct group name", async () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
let { wrapper } = setupMocks({});
|
let { wrapper } = setupMocks({
|
||||||
|
mountOptionsMockData: {
|
||||||
|
propsData: {
|
||||||
|
groupName: "radio-button-test",
|
||||||
|
value: "test value",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await wrapper.setProps({
|
|
||||||
groupName: "radio-button-test",
|
|
||||||
});
|
|
||||||
const input = wrapper.find("input");
|
const input = wrapper.find("input");
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
|
|
@ -20,12 +24,16 @@ describe("radio.vue", () => {
|
||||||
|
|
||||||
it("Should have correct label text", async () => {
|
it("Should have correct label text", async () => {
|
||||||
// Act
|
// Act
|
||||||
let { wrapper } = setupMocks({});
|
let { wrapper } = setupMocks({
|
||||||
|
mountOptionsMockData: {
|
||||||
|
propsData: {
|
||||||
|
buttonLabel: "label text",
|
||||||
|
value: "test value",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
// Arrange
|
// Arrange
|
||||||
await wrapper.setProps({
|
|
||||||
buttonLabel: "label text",
|
|
||||||
});
|
|
||||||
const paragraph = wrapper.find("p");
|
const paragraph = wrapper.find("p");
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
|
|
@ -39,6 +47,7 @@ describe("radio.vue", () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
await wrapper.setProps({
|
await wrapper.setProps({
|
||||||
screenReaderOnlyText: "screenreader text",
|
screenReaderOnlyText: "screenreader text",
|
||||||
|
value: "test value",
|
||||||
});
|
});
|
||||||
const paragraph = wrapper.find(".sr-only");
|
const paragraph = wrapper.find(".sr-only");
|
||||||
|
|
||||||
|
|
@ -48,13 +57,10 @@ describe("radio.vue", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
function setupMocks({ mountOptionsMockData = {} }) {
|
function setupMocks({ mountOptionsMockData = {} }) {
|
||||||
const wrapper = mount(
|
const wrapper = mount(radio, {
|
||||||
radio,
|
...mountOptionsMockData,
|
||||||
getMountOptions({
|
mixins: [inputButtonWrapperMixin],
|
||||||
...mountOptionsMockData,
|
});
|
||||||
mixins: [inputButtonWrapperMixin],
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
return { wrapper };
|
return { wrapper };
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
v-bind="$props"
|
v-bind="$props"
|
||||||
buttonWrapperClasses="ui-radio form-check"
|
buttonWrapperClasses="ui-radio form-check"
|
||||||
inputClasses="form-check-input"
|
inputClasses="form-check-input"
|
||||||
@buttonClicked="handleAnswerChange">
|
@inputButtonClicked="handleAnswerChange">
|
||||||
<div class="d-flex align-items-start form-check-label">
|
<div class="d-flex align-items-start form-check-label">
|
||||||
<p v-if="buttonLabel" class="m-0">{{ buttonLabel }}</p>
|
<p v-if="buttonLabel" class="m-0">{{ buttonLabel }}</p>
|
||||||
<span v-if="screenReaderOnlyText" class="sr-only">{{
|
<span v-if="screenReaderOnlyText" class="sr-only">{{
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue