From d695ab2c6458e523e33fcf710eccae63207ace15 Mon Sep 17 00:00:00 2001 From: Katie Date: Wed, 12 Oct 2022 13:46:18 -0400 Subject: [PATCH 1/9] CSR-762 Edit prettier file --- .prettierrc | 3 +- .../base-input-button.spec.js | 592 ++++++++++++++++-- .../base-input-button/base-input-button.vue | 15 +- 3 files changed, 547 insertions(+), 63 deletions(-) diff --git a/.prettierrc b/.prettierrc index 21209f49e..548cc94c4 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,4 +1,5 @@ { "tabWidth": 4, - "bracketSameLine": true + "bracketSameLine": true, + "printWidth": 100 } \ No newline at end of file diff --git a/src/common-components/base-input-button/base-input-button.spec.js b/src/common-components/base-input-button/base-input-button.spec.js index 190448df9..1cb244997 100644 --- a/src/common-components/base-input-button/base-input-button.spec.js +++ b/src/common-components/base-input-button/base-input-button.spec.js @@ -76,9 +76,7 @@ describe("baseInputButton.vue", () => { await wrapper.trigger("click"); // Assert - expect(wrapper.emitted()["inputButtonClicked"][0][0]).toEqual([ - "X", - ]); + expect(wrapper.emitted()["inputButtonClicked"][0][0]).toEqual(["X"]); }); }); @@ -99,22 +97,16 @@ describe("baseInputButton.vue", () => { await wrapper.trigger("click"); // Assert - expect(wrapper.emitted()["inputButtonClicked"][0][0]).toEqual( - "X" - ); + 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("focus on a checkbox => inputButtonClicked is not emitted"); - test.todo( - "blur from 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 @@ -133,9 +125,7 @@ describe("baseInputButton.vue", () => { await input.trigger("change"); // Assert - expect(wrapper.emitted()["inputButtonClicked"][0][0]).toEqual([ - "Hi", - ]); + expect(wrapper.emitted()["inputButtonClicked"][0][0]).toEqual(["Hi"]); }); test("focus and click space on a checkbox => inputButtonClicked is not emitted", async () => { @@ -155,9 +145,7 @@ describe("baseInputButton.vue", () => { await input.trigger("keypress", { key: "space" }); // Assert - expect(wrapper.emitted()).not.toHaveProperty( - "inputButtonClicked" - ); + expect(wrapper.emitted()).not.toHaveProperty("inputButtonClicked"); }); test("focus and click enter on a checkbox => inputButtonClicked is emitted with correct value", async () => { @@ -177,20 +165,14 @@ describe("baseInputButton.vue", () => { await input.trigger("keypress", { key: "enter" }); // Assert - expect(wrapper.emitted()["inputButtonClicked"][0][0]).toEqual([ - "Hi", - ]); + expect(wrapper.emitted()["inputButtonClicked"][0][0]).toEqual(["Hi"]); }); }); describe("radio", () => { - test.todo( - "focus on a radio button => inputButtonClicked is not emitted" - ); + test.todo("focus on a radio button => inputButtonClicked is not emitted"); - test.todo( - "blur from 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 @@ -210,9 +192,7 @@ describe("baseInputButton.vue", () => { // Assert expect(wrapper.emitted()).toHaveProperty("inputButtonClicked"); - expect(wrapper.emitted()["inputButtonClicked"][0][0]).toEqual( - "Hi" - ); + expect(wrapper.emitted()["inputButtonClicked"][0][0]).toEqual("Hi"); }); test("focus and click enter on a radio button => inputButtonClicked is emitted with correct value", async () => { @@ -233,44 +213,546 @@ describe("baseInputButton.vue", () => { // Assert expect(wrapper.emitted()).toHaveProperty("inputButtonClicked"); - expect(wrapper.emitted()["inputButtonClicked"][0][0]).toEqual( - "Hi" - ); + expect(wrapper.emitted()["inputButtonClicked"][0][0]).toEqual("Hi"); }); }); }); describe("methods", () => { - describe("handleEventAction", () => {}); + describe("handleEventAction", () => { + describe("isMultiSelect", () => { + test("eventType === eventTypes.CLICK => do nothing", () => { + // Arrange + const { wrapper } = setupMocks({ + mockData: { + propsData: { + isMultiSelect: true, + }, + }, + }); + wrapper.vm.handleClick = jest.fn(); + wrapper.vm.handlePushClickEventToGACheck = jest.fn(); + wrapper.vm.handleSelectionChange = jest.fn(); + + // Act + wrapper.vm.handleEventAction("click", { myEvent: "test" }); + + // Assert + expect(wrapper.vm.handleClick).not.toHaveBeenCalled(); + expect(wrapper.vm.handleSelectionChange).not.toHaveBeenCalled(); + expect(wrapper.vm.handlePushClickEventToGACheck).not.toHaveBeenCalled(); + }); + + test("eventType === eventTypes.ENTER => call handleClick and handlePushClickEventToGACheck", () => { + // Arrange + const { wrapper } = setupMocks({ + mockData: { + propsData: { + isMultiSelect: true, + }, + }, + }); + wrapper.vm.handleClick = jest.fn(); + wrapper.vm.handlePushClickEventToGACheck = jest.fn(); + wrapper.vm.handleSelectionChange = jest.fn(); + + // Act + wrapper.vm.handleEventAction("enter", { myEvent: "test" }); + + // Assert + expect(wrapper.vm.handleClick).toHaveBeenCalledWith({ + myEvent: "test", + }); + expect(wrapper.vm.handlePushClickEventToGACheck).toHaveBeenCalledWith("click"); + expect(wrapper.vm.handleSelectionChange).not.toHaveBeenCalled(); + }); + + test("eventType === eventTypes.CHANGE => call handleClick and handlePushClickEventToGACheck", () => { + // Arrange + const { wrapper } = setupMocks({ + mockData: { + propsData: { + isMultiSelect: true, + }, + }, + }); + wrapper.vm.handleClick = jest.fn(); + wrapper.vm.handlePushClickEventToGACheck = jest.fn(); + wrapper.vm.handleSelectionChange = jest.fn(); + + // Act + wrapper.vm.handleEventAction("change", { myEvent: "test" }); + + // Assert + expect(wrapper.vm.handleClick).toHaveBeenCalledWith({ + myEvent: "test", + }); + expect(wrapper.vm.handlePushClickEventToGACheck).toHaveBeenCalledWith("click"); + expect(wrapper.vm.handleSelectionChange).not.toHaveBeenCalled(); + }); + + test("eventType === eventTypes.MOUNT => do nothing", () => { + // Arrange + const { wrapper } = setupMocks({ + mockData: { + propsData: { + isMultiSelect: true, + }, + }, + }); + wrapper.vm.handleClick = jest.fn(); + wrapper.vm.handlePushClickEventToGACheck = jest.fn(); + wrapper.vm.handleSelectionChange = jest.fn(); + + // Act + wrapper.vm.handleEventAction("mount", { myEvent: "test" }); + + // Assert + expect(wrapper.vm.handleClick).not.toHaveBeenCalled(); + expect(wrapper.vm.handleSelectionChange).not.toHaveBeenCalled(); + expect(wrapper.vm.handlePushClickEventToGACheck).not.toHaveBeenCalled(); + }); + + test("eventType === eventTypes.SPACE => do nothing", () => { + // Arrange + const { wrapper } = setupMocks({ + mockData: { + propsData: { + isMultiSelect: true, + }, + }, + }); + wrapper.vm.handleClick = jest.fn(); + wrapper.vm.handlePushClickEventToGACheck = jest.fn(); + wrapper.vm.handleSelectionChange = jest.fn(); + + // Act + wrapper.vm.handleEventAction("space", { myEvent: "test" }); + + // Assert + expect(wrapper.vm.handleClick).not.toHaveBeenCalled(); + expect(wrapper.vm.handleSelectionChange).not.toHaveBeenCalled(); + expect(wrapper.vm.handlePushClickEventToGACheck).not.toHaveBeenCalled(); + }); + }); + + describe("!isMultiSelect", () => { + test("eventType === eventTypes.CLICK => call correct methods", () => { + // Arrange + const { wrapper } = setupMocks({ + mockData: { + propsData: { + isMultiSelect: false, + }, + }, + }); + wrapper.vm.handleClick = jest.fn(); + wrapper.vm.handlePushClickEventToGACheck = jest.fn(); + wrapper.vm.handleSelectionChange = jest.fn(); + + // Act + wrapper.vm.handleEventAction("click", { myEvent: "test" }); + + // Assert + expect(wrapper.vm.handleClick).toHaveBeenCalledWith({ + myEvent: "test", + }); + expect(wrapper.vm.handlePushClickEventToGACheck).toHaveBeenCalledWith("click"); + expect(wrapper.vm.handleSelectionChange).not.toHaveBeenCalled(); + }); + + test("eventType === eventTypes.ENTER => call correct methods", () => { + // Arrange + const { wrapper } = setupMocks({ + mockData: { + propsData: { + isMultiSelect: false, + }, + }, + }); + wrapper.vm.handleClick = jest.fn(); + wrapper.vm.handlePushClickEventToGACheck = jest.fn(); + wrapper.vm.handleSelectionChange = jest.fn(); + + // Act + wrapper.vm.handleEventAction("enter", { myEvent: "test" }); + + // Assert + expect(wrapper.vm.handleClick).toHaveBeenCalledWith({ + myEvent: "test", + }); + expect(wrapper.vm.handlePushClickEventToGACheck).toHaveBeenCalledWith("click"); + expect(wrapper.vm.handleSelectionChange).not.toHaveBeenCalled(); + }); + + test("eventType === eventTypes.SPACE => call correct methods", () => { + // Arrange + const { wrapper } = setupMocks({ + mockData: { + propsData: { + isMultiSelect: false, + }, + }, + }); + wrapper.vm.handleClick = jest.fn(); + wrapper.vm.handlePushClickEventToGACheck = jest.fn(); + wrapper.vm.handleSelectionChange = jest.fn(); + + // Act + wrapper.vm.handleEventAction("space", { myEvent: "test" }); + + // Assert + expect(wrapper.vm.handleClick).toHaveBeenCalledWith({ + myEvent: "test", + }); + expect(wrapper.vm.handlePushClickEventToGACheck).toHaveBeenCalledWith("click"); + expect(wrapper.vm.handleSelectionChange).not.toHaveBeenCalled(); + }); + + test("eventType === eventTypes.MOUNT => call correct methods", () => { + // Arrange + const { wrapper } = setupMocks({ + mockData: { + propsData: { + isMultiSelect: false, + }, + }, + }); + wrapper.vm.handleClick = jest.fn(); + wrapper.vm.handlePushClickEventToGACheck = jest.fn(); + wrapper.vm.handleSelectionChange = jest.fn(); + + // Act + wrapper.vm.handleEventAction("mount", { myEvent: "test" }); + + // Assert + expect(wrapper.vm.handleClick).toHaveBeenCalledWith({ + myEvent: "test", + }); + expect(wrapper.vm.handlePushClickEventToGACheck).toHaveBeenCalledWith("click"); + expect(wrapper.vm.handleSelectionChange).not.toHaveBeenCalled(); + }); + + test("eventType === eventTypes.CHANGE && selectOnKeypress => call correct methods", () => { + // Arrange + const { wrapper } = setupMocks({ + mockData: { + propsData: { + isMultiSelect: false, + selectOnKeypress: true, + }, + }, + }); + wrapper.vm.handleClick = jest.fn(); + wrapper.vm.handlePushClickEventToGACheck = jest.fn(); + wrapper.vm.handleSelectionChange = jest.fn(); + + // Act + wrapper.vm.handleEventAction("change", { myEvent: "test" }); + + // Assert + expect(wrapper.vm.handleSelectionChange).not.toHaveBeenCalled(); + expect(wrapper.vm.handleClick).toHaveBeenCalledWith({ + myEvent: "test", + }); + expect(wrapper.vm.handlePushClickEventToGACheck).not.toHaveBeenCalled(); + }); + + test("eventType === eventTypes.CHANGE && !selectOnKeypress => call correct methods", () => { + // Arrange + const { wrapper } = setupMocks({ + mockData: { + propsData: { + isMultiSelect: false, + selectOnKeypress: false, + }, + }, + }); + wrapper.vm.handleClick = jest.fn(); + wrapper.vm.handlePushClickEventToGACheck = jest.fn(); + wrapper.vm.handleSelectionChange = jest.fn(); + + // Act + wrapper.vm.handleEventAction("change", { myEvent: "test" }); + + // Assert + expect(wrapper.vm.handleSelectionChange).toHaveBeenCalledWith({ + myEvent: "test", + }); + expect(wrapper.vm.handleClick).not.toHaveBeenCalled(); + expect(wrapper.vm.handlePushClickEventToGACheck).not.toHaveBeenCalled(); + }); + }); + }); describe("handleSelectionChange", () => { - test.todo("handleChange is called with valueToEmit"); + const isCheckbox = [ + [true, ["Hi"]], + [false, "Hi"], + ]; + test.each(isCheckbox)( + "handleChange is called with valueToEmit", + (isMultiSelect, resultingValueToEmit) => { + // Arrange + const { wrapper } = setupMocks({ + mockData: { + propsData: { + isMultiSelect: isMultiSelect, + value: "Hi", + }, + }, + }); + + wrapper.vm.handleChange = jest.fn(); + + // Act + wrapper.vm.handleSelectionChange({ myEvent: "TEST" }); + + // Assert + expect(wrapper.vm.handleChange).toHaveBeenCalledWith(resultingValueToEmit); + } + ); describe("checkbox", () => { - test.todo("modelValue is null => valueToEmit is correct value"); + test("modelValue is null => valueToEmit is correct value", () => { + // Arrange + const { wrapper } = setupMocks({ + mockData: { + propsData: { + isMultiSelect: true, + value: "Bello", + modelValue: null, + }, + }, + }); - test.todo( - "modelValue is undefined => valueToEmit is correct value" - ); - test.todo( - "modelValue is empty => valueToEmit is correct value" - ); + wrapper.vm.handleChange = jest.fn(); - 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" + // Act + wrapper.vm.handleSelectionChange({ myEvent: "TEST" }); + + // Assert + expect(wrapper.vm.valueToEmit).toEqual(["Bello"]); + expect(wrapper.vm.handleChange).toHaveBeenCalledWith(["Bello"]); + }); + + test("modelValue is undefined => valueToEmit is correct value", () => { + // Arrange + const { wrapper } = setupMocks({ + mockData: { + propsData: { + isMultiSelect: true, + value: "Bello", + modelValue: undefined, + }, + }, + }); + + wrapper.vm.handleChange = jest.fn(); + + // Act + wrapper.vm.handleSelectionChange({ myEvent: "TEST" }); + + // Assert + expect(wrapper.vm.valueToEmit).toEqual(["Bello"]); + expect(wrapper.vm.handleChange).toHaveBeenCalledWith(["Bello"]); + }); + + test("modelValue is empty => valueToEmit is correct value", () => { + // Arrange + const { wrapper } = setupMocks({ + mockData: { + propsData: { + isMultiSelect: true, + value: "Bello", + modelValue: [], + }, + }, + }); + + wrapper.vm.handleChange = jest.fn(); + + // Act + wrapper.vm.handleSelectionChange({ myEvent: "TEST" }); + + // Assert + expect(wrapper.vm.valueToEmit).toEqual(["Bello"]); + expect(wrapper.vm.handleChange).toHaveBeenCalledWith(["Bello"]); + }); + + test("modelValue is not empty and does not contain this button's value => valueToEmit is correct value", () => { + // Arrange + const { wrapper } = setupMocks({ + mockData: { + propsData: { + isMultiSelect: true, + value: "Bello", + modelValue: ["Hello"], + }, + }, + }); + + wrapper.vm.handleChange = jest.fn(); + + // Act + wrapper.vm.handleSelectionChange({ myEvent: "TEST" }); + + // Assert + expect(wrapper.vm.valueToEmit).toEqual(["Hello", "Bello"]); + expect(wrapper.vm.handleChange).toHaveBeenCalledWith(["Hello", "Bello"]); + }); + + // testing when value is at start/middle/end of modelValue + const modelValues = [ + [["Bello", "Hello", "Mello"]], + [["Hello", "Bello", "Mello"]], + [["Hello", "Mello", "Bello"]], + ]; + test.each(modelValues)( + "modelValue is not empty and does contain this button's value => valueToEmit is correct value", + (modelValue) => { + // Arrange + const { wrapper } = setupMocks({ + mockData: { + propsData: { + isMultiSelect: true, + value: "Bello", + modelValue: modelValue, + }, + }, + }); + + wrapper.vm.handleChange = jest.fn(); + + // Act + wrapper.vm.handleSelectionChange({ myEvent: "TEST" }); + + // Assert + expect(wrapper.vm.valueToEmit).toEqual(["Hello", "Mello"]); + expect(wrapper.vm.handleChange).toHaveBeenCalledWith(["Hello", "Mello"]); + } ); }); - describe("radio", () => {}); + describe("radio", () => { + const modelValues = [null, undefined, "Bello", "Hello"]; + test.each(modelValues)( + "regardless of modelValue, set valueToEmit to correct value", + (modelValue) => { + // Arrange + const { wrapper } = setupMocks({ + mockData: { + propsData: { + isMultiSelect: false, + value: "Bello", + modelValue: modelValue, + }, + }, + }); + + wrapper.vm.handleChange = jest.fn(); + + // Act + wrapper.vm.handleSelectionChange({ myEvent: "TEST" }); + + // Assert + expect(wrapper.vm.valueToEmit).toEqual("Bello"); + expect(wrapper.vm.handleChange).toHaveBeenCalledWith("Bello"); + } + ); + }); }); describe("handleClick", () => { - test.todo("handleSelectChange is also called"); + const isCheckbox = [[true], [false]]; + test.each(isCheckbox)("handleSelectionChange is also called", async (isMultiSelect) => { + // Arrange + const { wrapper } = setupMocks({ + mockData: { + propsData: { + isMultiSelect: isMultiSelect, + value: "Bello", + }, + }, + }); - test.todo("inputButtonClicked is emitted with valueToEmit"); + wrapper.vm.handleSelectionChange = jest.fn(); + await wrapper.setData({ valueToEmit: "HELLO WORLD" }); + + // Act + wrapper.vm.handleClick({ myEvent: "Test" }); + + // Assert + expect(wrapper.vm.handleSelectionChange).toHaveBeenCalledWith({ myEvent: "Test" }); + }); + + test.each(isCheckbox)("inputButtonClicked is emitted with valueToEmit", async () => { + // Arrange + const { wrapper } = setupMocks({ + mockData: { + propsData: { + isMultiSelect: isMultiSelect, + value: "Bello", + }, + }, + }); + + wrapper.vm.handleSelectionChange = jest.fn(); + await wrapper.setData({ valueToEmit: "HELLO WORLD" }); + + // Act + wrapper.vm.handleClick({ myEvent: "Test" }); + + // Assert + expect(wrapper.emitted()["inputButtonClicked"][0][0]).toEqual("HELLO WORLD"); + }); + }); + + describe("handlePushClickEventToGACheck", () => { + test.todo(""); + }); + + describe("pushClickEventToGA", () => { + test.only("pushEventToGA is called correctly", () => { + // Arrange + const { wrapper } = setupMocks({ + mockData: { + propsData: { + value: "Bello", + setLastValuePushedToGa: jest.fn(), + }, + route: { + query: { + fmgPage: "myPage", + }, + }, + }, + }); + + console.log(wrapper.vm.$route) + + wrapper.vm.pushEventToGA = jest.fn(); + wrapper.setData({ + GaActions: { + CLICKED: "Clicked", + }, + }); + + // Act + wrapper.vm.pushClickEventToGA(); + + // Assert + expect(wrapper.vm.pushEventToGA).toHaveBeenCalledWith( + "myPage", + "Clicked", + "Bello", + true, + undefined + ); + expect(wrapper.vm.setLastValuePushedToGa).toHaveBeenCalledWith("Bello"); + }); + + test.todo("set last value pushed to GA"); }); }); @@ -413,9 +895,7 @@ describe("baseInputButton.vue", () => { // 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" - ); + 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", () => { @@ -472,7 +952,9 @@ describe("baseInputButton.vue", () => { }); }); -// 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) +// 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 = { @@ -505,7 +987,7 @@ function setupMocks({ mockData = {}, shouldShallowMount = true }) { wrapper.vm.$route = { query: {}, }; - wrapper.vm.GaActions = {} + wrapper.vm.GaActions = {}; return { wrapper }; } diff --git a/src/common-components/base-input-button/base-input-button.vue b/src/common-components/base-input-button/base-input-button.vue index 8cd50278e..b5899a3a8 100644 --- a/src/common-components/base-input-button/base-input-button.vue +++ b/src/common-components/base-input-button/base-input-button.vue @@ -4,7 +4,7 @@ :for="buttonId" @focusin="handleFocus" @focusout="handleBlur" - @mousedown.left="handleEventAction('click', $event)"> + @mousedown.left="handleEventAction(eventTypes.CLICK, $event)"> + @keypress.space="handleEventAction(eventTypes.SPACE, $event)" + @keypress.enter="handleEventAction(eventTypes.ENTER, $event)" + @change="handleEventAction(eventTypes.CHANGE, $event)" /> @@ -124,7 +124,7 @@ export default { } this.valueToEmit = newValue; - } else { + } else if (!this.isMultiSelect) { this.valueToEmit = this.value; } @@ -146,9 +146,10 @@ export default { }); }, handlePushClickEventToGACheck(source) { + // if from a click or click-like event if (source === this.eventTypes.CLICK) { this.pushClickEventToGA(); - } else { + } else { // if from tabbing around if ( !this.isValueSelectedOnClick && this.isChecked && @@ -167,7 +168,7 @@ export default { this.valueToLogType ); - this.setLastValuePushedToGa(this.value); + this.setLastValuePushedToGa(value ?? this.value); }, }, computed: { From f8531348701e481ad9cc2ea8fb7a82024d810513 Mon Sep 17 00:00:00 2001 From: Katie Date: Thu, 13 Oct 2022 09:58:01 -0400 Subject: [PATCH 2/9] CSR-762 tests WIP --- .../base-input-button.spec.js | 72 +++++++++++-------- 1 file changed, 41 insertions(+), 31 deletions(-) diff --git a/src/common-components/base-input-button/base-input-button.spec.js b/src/common-components/base-input-button/base-input-button.spec.js index 1cb244997..3f1b03d9c 100644 --- a/src/common-components/base-input-button/base-input-button.spec.js +++ b/src/common-components/base-input-button/base-input-button.spec.js @@ -1,5 +1,6 @@ import { shallowMount, mount } from "@vue/test-utils"; import baseInputButton from "./base-input-button"; +import inputButtonWrapperMixin from "@/mixins/input-button-wrapper-mixin" describe("baseInputButton.vue", () => { describe("general", () => { @@ -713,7 +714,7 @@ describe("baseInputButton.vue", () => { }); describe("pushClickEventToGA", () => { - test.only("pushEventToGA is called correctly", () => { + test("pushEventToGA is called correctly", () => { // Arrange const { wrapper } = setupMocks({ mockData: { @@ -721,17 +722,11 @@ describe("baseInputButton.vue", () => { value: "Bello", setLastValuePushedToGa: jest.fn(), }, - route: { - query: { - fmgPage: "myPage", - }, - }, }, }); - console.log(wrapper.vm.$route) + console.log(wrapper.vm.$route); - wrapper.vm.pushEventToGA = jest.fn(); wrapper.setData({ GaActions: { CLICKED: "Clicked", @@ -950,6 +945,25 @@ describe("baseInputButton.vue", () => { }); }); }); + + describe("integration testing", () => { + describe("checkbox", () => { + test.only("click on both => both are selected", async () => { + // Arrange + const { wrapper } = setupBaseInputButtonWrapper({ + isMultiSelect: true + }) + console.log(wrapper.html()) + + // Act + const buttonWrappers = wrapper.findAllComponents({name: "baseInputButtonWrapper"}) + await buttonWrappers[0].trigger("click") + + // Assert + expect(wrapper.vm.value).toEqual(["value1"]) + }) + }) + }); }); // TODO KO look at how I tested groups of these in SFA @@ -957,15 +971,6 @@ describe("baseInputButton.vue", () => { // that this acts like a regular input aside from a different emitted event) function setupMocks({ mockData = {}, shouldShallowMount = true }) { - const baseInputButtonWrapper = { - components: { baseInputButton }, - template: '', - data() { - return { - myValue: "", - }; - }, - }; const mountMockData = { ...mockData, propsData: { @@ -985,7 +990,9 @@ function setupMocks({ mockData = {}, shouldShallowMount = true }) { wrapper.vm.pushEventToGA = jest.fn(); wrapper.vm.$route = { - query: {}, + query: { + fmgPage: "myPage", + }, }; wrapper.vm.GaActions = {}; @@ -994,28 +1001,31 @@ function setupMocks({ mockData = {}, shouldShallowMount = true }) { function setupBaseInputButtonWrapper({ mockData = {} }) { const baseInputButtonWrapper = { + name: "baseInputButtonWrapper", components: { baseInputButton }, template: - '
', + '
Test
', data() { return { - myValue: "", isMultiSelect: mockData.isMultiSelect, }; }, - - // const parentComponent = mount({ - // data() { - // return { - // value: "value1", - // } - // }, - // template: '
', - // components: { baseInputButton } - // }) + mixins: [inputButtonWrapperMixin] }; - const wrapper = mount(baseInputButtonWrapper, {}); + let parentComponentTemplate = "
" + parentComponentTemplate += `` + parentComponentTemplate += `` + parentComponentTemplate += `
` + const wrapper = mount({ + data() { + return { + value: mockData.initialValue, + } + }, + template: parentComponentTemplate, + components: { baseInputButtonWrapper } + }) return { wrapper }; } From 782dcfd8a649a78af625562f603d270e7025f245 Mon Sep 17 00:00:00 2001 From: Katie Date: Mon, 17 Oct 2022 12:07:44 -0400 Subject: [PATCH 3/9] CSR-762 Fix merge conflict --- src/helpers/button-question-focus-helper.js | 42 +++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 src/helpers/button-question-focus-helper.js diff --git a/src/helpers/button-question-focus-helper.js b/src/helpers/button-question-focus-helper.js new file mode 100644 index 000000000..9884fa041 --- /dev/null +++ b/src/helpers/button-question-focus-helper.js @@ -0,0 +1,42 @@ +/** + * Helper for GA click event. When the user mouse clicks on a `base-input-button`, we + * push the click event. When the user tabs through a list of radio buttons via a + * keyboard, we only want to push the GA click event if the selection was deliberate + * (space/enter key) or if there is a selection and the user tabs off of the radio group. + */ + +let lastFocusedInputGroupName = ""; +let onButtonQuestionLostFocusCallback = null; + +// TODO KO add tests +const handleAnyComponentFocus = (e) => { + const targetType = e.target.type; + if (targetType !== "radio" && targetType !== "checkbox") { + invokeButtonQuestionLostFocusCallback(); + } +}; + +const handleButtonComponentFocus = (e) => { + if (e && lastFocusedInputGroupName !== e.groupName) { + invokeButtonQuestionLostFocusCallback(); + } +}; + +const handleInputComponentBlur = (e) => { + if (e) { + lastFocusedInputGroupName = e.groupName; + onButtonQuestionLostFocusCallback = e.onButtonQuestionLostFocusCallback; + } +}; + +const invokeButtonQuestionLostFocusCallback = () => { + if (onButtonQuestionLostFocusCallback) { + onButtonQuestionLostFocusCallback(); + } +}; + +export { + handleAnyComponentFocus, + handleButtonComponentFocus, + handleInputComponentBlur, +}; From b77aded229b4d3232366c65e3c201ab5636c5fd4 Mon Sep 17 00:00:00 2001 From: Katie Date: Thu, 20 Oct 2022 08:29:35 -0400 Subject: [PATCH 4/9] WIP --- .../base-input-button.spec.js | 337 ++++++++++-------- .../base-input-button/base-input-button.vue | 3 +- 2 files changed, 185 insertions(+), 155 deletions(-) diff --git a/src/common-components/base-input-button/base-input-button.spec.js b/src/common-components/base-input-button/base-input-button.spec.js index 697b3ac53..75982cf73 100644 --- a/src/common-components/base-input-button/base-input-button.spec.js +++ b/src/common-components/base-input-button/base-input-button.spec.js @@ -1,6 +1,6 @@ import { shallowMount, mount } from "@vue/test-utils"; import baseInputButton from "./base-input-button"; -import inputButtonWrapperMixin from "@/mixins/input-button-wrapper-mixin" +import inputButtonWrapperMixin from "@/mixins/input-button-wrapper-mixin"; // TODO KO describe("baseInputButton.vue", () => { @@ -62,26 +62,109 @@ describe("baseInputButton.vue", () => { describe("mouse clicks", () => { describe("checkbox", () => { - test("clicked => correct event and value are emitted", async () => { - // Arrange - const { wrapper } = setupMocks({ - mockData: { - propsData: { - isMultiSelect: true, - value: "X", + describe("clicked once", () => { + test("correct event and value are emitted", async () => { + // Arrange + const { wrapper } = setupMocks({ + mockData: { + propsData: { + isMultiSelect: true, + value: "X", + }, }, - }, + }); + + // Act + await wrapper.trigger("click"); + + // Assert + expect(wrapper.emitted()["update:modelValue"][0][0]).toEqual(["X"]); }); + + test("input is checked", async () => { + // Arrange + const { wrapper } = setupMocks({ + mockData: { + propsData: { + isMultiSelect: true, + value: "X", + }, + }, + }); + const input = wrapper.find("input"); + + // Act + await wrapper.trigger("click"); + + + // Assert + expect(input.element.checked).toBe(true); + }); + }) + + describe("clicked twice" ,() => { + test("input is unchecked", async () => { + // Arrange + const { wrapper } = setupMocks({ + mockData: { + propsData: { + isMultiSelect: true, + value: "X", + }, + }, + }); + const input = wrapper.find("input"); + + // Act + await wrapper.trigger("click"); + await wrapper.trigger("click"); + + // Assert + expect(input.element.checked).toBe(false); + }); + }) - // Act - // await wrapper.trigger("mousedown.left"); - await wrapper.trigger("click"); - - // Assert - expect(wrapper.emitted()["update:modelValue"][0][0]).toEqual([ - "X", - ]); - }); + describe("is initially checked, click once", () => { + test("input is unchecked", async () => { + // Arrange + const { wrapper } = setupMocks({ + mockData: { + propsData: { + isMultiSelect: true, + value: "X", + modelValue:["X"] + }, + }, + }); + const input = wrapper.find("input"); + + // Act + await wrapper.trigger("click"); + + // Assert + expect(input.element.checked).toBe(false); + }); + + test("input is unchecked", async () => { + // Arrange + const { wrapper } = setupMocks({ + mockData: { + propsData: { + isMultiSelect: true, + value: "X", + modelValue:["X"] + }, + }, + }); + const input = wrapper.find("input"); + + // Act + await wrapper.trigger("click"); + + // Assert + expect(input.element.checked).toBe(false); + }); + }) }); describe("radio", () => { @@ -101,9 +184,7 @@ describe("baseInputButton.vue", () => { await wrapper.trigger("click"); // Assert - expect(wrapper.emitted()["update:modelValue"][0][0]).toEqual( - "X" - ); + expect(wrapper.emitted()["update:modelValue"][0][0]).toEqual("X"); }); }); }); @@ -131,9 +212,7 @@ describe("baseInputButton.vue", () => { await input.trigger("change"); // Assert - expect(wrapper.emitted()["update:modelValue"][0][0]).toEqual([ - "Hi", - ]); + expect(wrapper.emitted()["update:modelValue"][0][0]).toEqual(["Hi"]); }); test("focus and click space on a checkbox => update:modelValue is not emitted", async () => { @@ -153,9 +232,7 @@ describe("baseInputButton.vue", () => { await input.trigger("keypress", { key: "space" }); // Assert - expect(wrapper.emitted()).not.toHaveProperty( - "update:modelValue" - ); + expect(wrapper.emitted()).not.toHaveProperty("update:modelValue"); }); test("focus and click enter on a checkbox => update:modelValue is emitted with correct value", async () => { @@ -175,9 +252,7 @@ describe("baseInputButton.vue", () => { await input.trigger("keypress", { key: "enter" }); // Assert - expect(wrapper.emitted()["update:modelValue"][0][0]).toEqual([ - "Hi", - ]); + expect(wrapper.emitted()["update:modelValue"][0][0]).toEqual(["Hi"]); }); }); @@ -204,9 +279,7 @@ describe("baseInputButton.vue", () => { // Assert expect(wrapper.emitted()).toHaveProperty("update:modelValue"); - expect(wrapper.emitted()["update:modelValue"][0][0]).toEqual( - "Hi" - ); + expect(wrapper.emitted()["update:modelValue"][0][0]).toEqual("Hi"); }); test("focus and click enter on a radio button => update:modelValue is emitted with correct value", async () => { @@ -227,9 +300,7 @@ describe("baseInputButton.vue", () => { // Assert expect(wrapper.emitted()).toHaveProperty("update:modelValue"); - expect(wrapper.emitted()["update:modelValue"][0][0]).toEqual( - "Hi" - ); + expect(wrapper.emitted()["update:modelValue"][0][0]).toEqual("Hi"); }); }); }); @@ -678,26 +749,29 @@ describe("baseInputButton.vue", () => { expect(wrapper.vm.handleSelectionChange).toHaveBeenCalledWith({ myEvent: "Test" }); }); - test.each(isCheckbox)("update:modelValue is emitted with valueToEmit", async (isMultiSelect) => { - // Arrange - const { wrapper } = setupMocks({ - mockData: { - propsData: { - isMultiSelect: isMultiSelect, - value: "Bello", + test.each(isCheckbox)( + "update:modelValue is emitted with valueToEmit", + async (isMultiSelect) => { + // Arrange + const { wrapper } = setupMocks({ + mockData: { + propsData: { + isMultiSelect: isMultiSelect, + value: "Bello", + }, }, - }, - }); + }); - wrapper.vm.handleSelectionChange = jest.fn(); - await wrapper.setData({ valueToEmit: "HELLO WORLD" }); + wrapper.vm.handleSelectionChange = jest.fn(); + await wrapper.setData({ valueToEmit: "HELLO WORLD" }); - // Act - wrapper.vm.handleClick({ myEvent: "Test" }); + // Act + wrapper.vm.handleClick({ myEvent: "Test" }); - // Assert - expect(wrapper.emitted()["update:modelValue"][0][0]).toEqual("HELLO WORLD"); - }); + // Assert + expect(wrapper.emitted()["update:modelValue"][0][0]).toEqual("HELLO WORLD"); + } + ); }); describe("handlePushClickEventToGACheck", () => { @@ -994,32 +1068,35 @@ describe("baseInputButton.vue", () => { [["value2"], false, true], [["value1", "value2"], true, true], [["value1"], true, false], - [[], false, false] - ] - test.each(defaultCheckedCases)("initial value is %s => correct input buttons are selected", async (modelValue, isInputButtonOneChecked, isInputButtonTwoChecked) => { - // Arrange - const { wrapper } = setupBaseInputButtonWrapper({ - mockData: { - isMultiSelect: true, - initialValue: modelValue - }, - }); + [[], false, false], + ]; + test.each(defaultCheckedCases)( + "initial value is %s => correct input buttons are selected", + async (modelValue, isInputButtonOneChecked, isInputButtonTwoChecked) => { + // Arrange + const { wrapper } = setupBaseInputButtonWrapper({ + mockData: { + isMultiSelect: true, + initialValue: modelValue, + }, + }); - // Act - const buttonWrappers = wrapper.findAllComponents({ - name: "baseInputButtonWrapper", - }); - const inputs = wrapper.findAll("input"); - const inputButtonOne = buttonWrappers.at(0); - const inputButtonTwo = buttonWrappers.at(1); + // Act + const buttonWrappers = wrapper.findAllComponents({ + name: "baseInputButtonWrapper", + }); + const inputs = wrapper.findAll("input"); + const inputButtonOne = buttonWrappers.at(0); + const inputButtonTwo = buttonWrappers.at(1); - // Assert - expect(inputButtonOne.vm.isMultiSelect).toBe(true); - expect(inputButtonTwo.vm.isMultiSelect).toBe(true); - expect(inputs[0].element.checked).toBe(isInputButtonOneChecked); - expect(inputs[1].element.checked).toBe(isInputButtonTwoChecked); - expect(wrapper.vm.value).toEqual(modelValue); - }); + // Assert + expect(inputButtonOne.vm.isMultiSelect).toBe(true); + expect(inputButtonTwo.vm.isMultiSelect).toBe(true); + expect(inputs[0].element.checked).toBe(isInputButtonOneChecked); + expect(inputs[1].element.checked).toBe(isInputButtonTwoChecked); + expect(wrapper.vm.value).toEqual(modelValue); + } + ); }); describe("radio", () => { @@ -1078,51 +1155,40 @@ describe("baseInputButton.vue", () => { ["", false, false], ["value1", true, false], ["value2", false, true], - [[], false, false] - ] - test.each(defaultCheckedCases)("initial value is %s => correct input buttons are selected", async (modelValue, isInputButtonOneChecked, isInputButtonTwoChecked) => { - // Arrange - const { wrapper } = setupBaseInputButtonWrapper({ - mockData: { - isMultiSelect: false, - initialValue: modelValue - }, - }); + [[], false, false], + ]; + test.each(defaultCheckedCases)( + "initial value is %s => correct input buttons are selected", + async (modelValue, isInputButtonOneChecked, isInputButtonTwoChecked) => { + // Arrange + const { wrapper } = setupBaseInputButtonWrapper({ + mockData: { + isMultiSelect: false, + initialValue: modelValue, + }, + }); - // Act - const buttonWrappers = wrapper.findAllComponents({ - name: "baseInputButtonWrapper", - }); - const inputs = wrapper.findAll("input"); - const inputButtonOne = buttonWrappers.at(0); - const inputButtonTwo = buttonWrappers.at(1); + // Act + const buttonWrappers = wrapper.findAllComponents({ + name: "baseInputButtonWrapper", + }); + const inputs = wrapper.findAll("input"); + const inputButtonOne = buttonWrappers.at(0); + const inputButtonTwo = buttonWrappers.at(1); - // Assert - expect(inputButtonOne.vm.isMultiSelect).toBe(false); - expect(inputButtonTwo.vm.isMultiSelect).toBe(false); - expect(inputs[0].element.checked).toBe(isInputButtonOneChecked); - expect(inputs[1].element.checked).toBe(isInputButtonTwoChecked); - expect(wrapper.vm.value).toEqual(modelValue); - }); - }) + // Assert + expect(inputButtonOne.vm.isMultiSelect).toBe(false); + expect(inputButtonTwo.vm.isMultiSelect).toBe(false); + expect(inputs[0].element.checked).toBe(isInputButtonOneChecked); + expect(inputs[1].element.checked).toBe(isInputButtonTwoChecked); + expect(wrapper.vm.value).toEqual(modelValue); + } + ); + }); }); }); -// 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: '', - data() { - return { - myValue: "", - }; - }, - }; - const mountMockData = { ...mockData, propsData: { @@ -1152,34 +1218,6 @@ function setupMocks({ mockData = {}, shouldShallowMount = true }) { } function setupBaseInputButtonWrapper({ mockData = {} }) { -// <<<<<<< HEAD -// const baseInputButtonWrapper = { -// name: "baseInputButtonWrapper", -// components: { baseInputButton }, -// template: -// '
Test
', -// data() { -// return { -// isMultiSelect: mockData.isMultiSelect, -// }; -// }, -// mixins: [inputButtonWrapperMixin] -// }; - -// let parentComponentTemplate = "
" -// parentComponentTemplate += `` -// parentComponentTemplate += `` -// parentComponentTemplate += `
` -// const wrapper = mount({ -// data() { -// return { -// value: mockData.initialValue, -// } -// }, -// template: parentComponentTemplate, -// components: { baseInputButtonWrapper } -// }) -// ======= const originalData = baseInputButton.data(); baseInputButton.data = () => { return { @@ -1192,19 +1230,15 @@ function setupBaseInputButtonWrapper({ mockData = {} }) { }; }; - // console.log({ - // test: baseInputButton.vm.$route - // }) baseInputButton.methods.pushClickEventToGA = jest.fn(); const baseInputButtonWrapper = { name: "baseInputButtonWrapper", components: { baseInputButton }, - template: - '
', + template: '
', mixins: [inputButtonWrapperMixin], }; - + let parentComponentTemplate = `
`; parentComponentTemplate += ``; parentComponentTemplate += ``; @@ -1213,9 +1247,7 @@ function setupBaseInputButtonWrapper({ mockData = {} }) { { data() { return { - value: - mockData.initialValue ?? - (mockData.isMultiSelect ? [] : ""), + value: mockData.initialValue ?? (mockData.isMultiSelect ? [] : ""), $route: { query: { fmgPage: "myPage", @@ -1228,7 +1260,6 @@ function setupBaseInputButtonWrapper({ mockData = {} }) { }, {} ); -// >>>>>>> feature/CSR-762 return { wrapper }; } diff --git a/src/common-components/base-input-button/base-input-button.vue b/src/common-components/base-input-button/base-input-button.vue index f36e7b126..3f4fd4c2c 100644 --- a/src/common-components/base-input-button/base-input-button.vue +++ b/src/common-components/base-input-button/base-input-button.vue @@ -97,6 +97,7 @@ export default { }, handleClick(e) { this.handleSelectionChange(e); + console.log(this.valueToEmit) this.$emit("update:modelValue", this.valueToEmit); }, handleFocus() { @@ -126,8 +127,6 @@ export default { } }, pushClickEventToGA(value) { - console.log("PUSHHH") - console.log(this.$route) this.pushEventToGA( this.$route.query[queryStrings.FMG_PAGE], this.GaActions.CLICKED, From 33faaac7bc064438ed5dcb5b37f19f58ae787404 Mon Sep 17 00:00:00 2001 From: Katie Date: Thu, 20 Oct 2022 09:58:51 -0400 Subject: [PATCH 5/9] CSR-762 button-question-focus-helper tests --- .../button-question-focus-helper.spec.js | 251 ++++++++++++++++++ 1 file changed, 251 insertions(+) create mode 100644 src/helpers/button-question-focus-helper.spec.js diff --git a/src/helpers/button-question-focus-helper.spec.js b/src/helpers/button-question-focus-helper.spec.js new file mode 100644 index 000000000..0d6483d20 --- /dev/null +++ b/src/helpers/button-question-focus-helper.spec.js @@ -0,0 +1,251 @@ +import { + handleAnyComponentFocus, + handleButtonComponentFocus, + handleInputComponentBlur, +} from "@/helpers/button-question-focus-helper"; + +describe("buttonQuestionFocusHelper", () => { + let onButtonQuestionLostFocusCallbackOne = jest.fn(); + let onButtonQuestionLostFocusCallbackTwo = jest.fn(); + + let focusOnInputInGroupOne; + let blurFromInputInGroupOne; + let focusOnInputInGroupTwo; + let blurFromInputInGroupTwo; + + let focusOnNonRadioCheckboxElement; + + beforeEach(() => { + onButtonQuestionLostFocusCallbackOne = jest.fn(); + onButtonQuestionLostFocusCallbackTwo = jest.fn(); + + // Sanity check + expect(onButtonQuestionLostFocusCallbackOne).not.toHaveBeenCalled(); + expect(onButtonQuestionLostFocusCallbackTwo).not.toHaveBeenCalled(); + + focusOnInputInGroupOne = () => { + handleButtonComponentFocus({ + groupName: "group1", + }); + }; + + blurFromInputInGroupOne = () => { + handleInputComponentBlur({ + groupName: "group1", + onButtonQuestionLostFocusCallback: onButtonQuestionLostFocusCallbackOne, + }); + }; + + focusOnInputInGroupTwo = () => { + handleButtonComponentFocus({ + groupName: "group2", + }); + }; + + blurFromInputInGroupTwo = () => { + handleInputComponentBlur({ + groupName: "group2", + onButtonQuestionLostFocusCallback: onButtonQuestionLostFocusCallbackTwo, + }); + }; + + focusOnNonRadioCheckboxElement = () => { + handleAnyComponentFocus({ + target: { + type: "nonRadioCheckbox", + }, + }); + }; + }); + + test("focus on input => no callbacks were called", () => { + // focus on input in group 1 + focusOnInputInGroupOne(); + + // Assert + expect(onButtonQuestionLostFocusCallbackOne).not.toHaveBeenCalled(); + expect(onButtonQuestionLostFocusCallbackTwo).not.toHaveBeenCalled(); + }); + + test("focus on input, then focus on input in same group => no callbacks are called", () => { + // focus on input in group 1 + focusOnInputInGroupOne(); + + // Assert + expect(onButtonQuestionLostFocusCallbackOne).not.toHaveBeenCalled(); + expect(onButtonQuestionLostFocusCallbackTwo).not.toHaveBeenCalled(); + + // focus on input in group 1 + blurFromInputInGroupOne(); + focusOnInputInGroupOne(); + + // Assert + expect(onButtonQuestionLostFocusCallbackOne).not.toHaveBeenCalled(); + expect(onButtonQuestionLostFocusCallbackTwo).not.toHaveBeenCalled(); + }); + + test("focus on non-radio/checkbox, focus on input => no callbacks are called", () => { + // focus on non-radio/checkbox + focusOnNonRadioCheckboxElement(); + + // Assert + expect(onButtonQuestionLostFocusCallbackOne).not.toHaveBeenCalled(); + expect(onButtonQuestionLostFocusCallbackTwo).not.toHaveBeenCalled(); + + // focus on input + // focus on input in group 1 + focusOnInputInGroupOne(); + + // Assert + expect(onButtonQuestionLostFocusCallbackOne).not.toHaveBeenCalled(); + expect(onButtonQuestionLostFocusCallbackTwo).not.toHaveBeenCalled(); + }); + + test("focus on input in group 1, then focus on input in different group => callback for group 1 is called", () => { + // focus on input in group 1 + focusOnInputInGroupOne(); + + // Assert + expect(onButtonQuestionLostFocusCallbackOne).not.toHaveBeenCalled(); + expect(onButtonQuestionLostFocusCallbackTwo).not.toHaveBeenCalled(); + + // focus on input in different group + blurFromInputInGroupOne(); + focusOnInputInGroupTwo(); + + // Assert + expect(onButtonQuestionLostFocusCallbackOne).toHaveBeenCalledTimes(1); + expect(onButtonQuestionLostFocusCallbackTwo).not.toHaveBeenCalled(); + }); + + test("focus on input in group 1, focus on input in same group, then focus on input in different group => callback for group 1 is called", () => { + // focus on input in group 1 + focusOnInputInGroupOne(); + + // Assert + expect(onButtonQuestionLostFocusCallbackOne).not.toHaveBeenCalled(); + expect(onButtonQuestionLostFocusCallbackTwo).not.toHaveBeenCalled(); + + // focus on input in same group + blurFromInputInGroupOne(); + focusOnInputInGroupOne(); + + // Assert + expect(onButtonQuestionLostFocusCallbackOne).not.toHaveBeenCalled(); + expect(onButtonQuestionLostFocusCallbackTwo).not.toHaveBeenCalled(); + + // focus on input in different group + blurFromInputInGroupOne(); + focusOnInputInGroupTwo(); + + // Assert + expect(onButtonQuestionLostFocusCallbackOne).toHaveBeenCalledTimes(1); + expect(onButtonQuestionLostFocusCallbackTwo).not.toHaveBeenCalled(); + }); + + test("focus on input in group 1, focus on non-radio/checkbox element => callback from group 1 is called", () => { + // focus on input in group 1 + focusOnInputInGroupOne(); + + // Assert + expect(onButtonQuestionLostFocusCallbackOne).not.toHaveBeenCalled(); + expect(onButtonQuestionLostFocusCallbackTwo).not.toHaveBeenCalled(); + + // focus on input in group 2 + blurFromInputInGroupOne(); + focusOnNonRadioCheckboxElement(); + + // Assert + expect(onButtonQuestionLostFocusCallbackOne).toHaveBeenCalledTimes(1); + expect(onButtonQuestionLostFocusCallbackTwo).not.toHaveBeenCalled(); + }); + + test("focus on input in group 1, focus on input in group 2, focus on non-radio/checkbox element => both callbacks are called", () => { + // focus on input in group 1 + focusOnInputInGroupOne(); + + // Assert + expect(onButtonQuestionLostFocusCallbackOne).not.toHaveBeenCalled(); + expect(onButtonQuestionLostFocusCallbackTwo).not.toHaveBeenCalled(); + + // focus on input in group 2 + blurFromInputInGroupOne(); + focusOnInputInGroupTwo(); + + // Assert + expect(onButtonQuestionLostFocusCallbackOne).toHaveBeenCalledTimes(1); + expect(onButtonQuestionLostFocusCallbackTwo).toHaveBeenCalledTimes(0); + + // focus on non-radio/checkbox + blurFromInputInGroupTwo(); + focusOnNonRadioCheckboxElement(); + + // Assert + expect(onButtonQuestionLostFocusCallbackOne).toHaveBeenCalledTimes(1); + expect(onButtonQuestionLostFocusCallbackTwo).toHaveBeenCalledTimes(1); + }); + + test("focus on input in group 1, focus on input in group 2, focus on input in group 1 => both callbacks are called", () => { + // focus on input in group 1 + focusOnInputInGroupOne(); + + // Assert + expect(onButtonQuestionLostFocusCallbackOne).not.toHaveBeenCalled(); + expect(onButtonQuestionLostFocusCallbackTwo).not.toHaveBeenCalled(); + + // focus on input in group 2 + blurFromInputInGroupOne(); + focusOnInputInGroupTwo(); + + // Assert + expect(onButtonQuestionLostFocusCallbackOne).toHaveBeenCalledTimes(1); + expect(onButtonQuestionLostFocusCallbackTwo).toHaveBeenCalledTimes(0); + + // focus on input in group 1 + blurFromInputInGroupTwo(); + focusOnInputInGroupOne(); + + // Assert + expect(onButtonQuestionLostFocusCallbackOne).toHaveBeenCalledTimes(1); + expect(onButtonQuestionLostFocusCallbackTwo).toHaveBeenCalledTimes(1); + }); + + test("go back and forth a lot => correct callbacks are called at the right time", () => { + // Arrange/Act + // focus on input in group 1 + focusOnInputInGroupOne(); + + // Assert + expect(onButtonQuestionLostFocusCallbackOne).not.toHaveBeenCalled(); + expect(onButtonQuestionLostFocusCallbackTwo).not.toHaveBeenCalled(); + + // focus on input in group 2 + blurFromInputInGroupOne(); + focusOnInputInGroupTwo(); + + // Assert + expect(onButtonQuestionLostFocusCallbackOne).toHaveBeenCalledTimes(1); + expect(onButtonQuestionLostFocusCallbackTwo).not.toHaveBeenCalled(); + + // focus on input in group 1 + blurFromInputInGroupTwo(); + focusOnInputInGroupOne(); + + // Assert + expect(onButtonQuestionLostFocusCallbackOne).toHaveBeenCalledTimes(1); + expect(onButtonQuestionLostFocusCallbackTwo).toHaveBeenCalledTimes(1); + + // focus on non-radio/checkbox element + blurFromInputInGroupOne(); + focusOnNonRadioCheckboxElement(); + + // Assert + expect(onButtonQuestionLostFocusCallbackOne).toHaveBeenCalledTimes(2); + expect(onButtonQuestionLostFocusCallbackTwo).toHaveBeenCalledTimes(1); + + // focus on input in group 1 + focusOnInputInGroupOne(); + expect(onButtonQuestionLostFocusCallbackOne).toHaveBeenCalledTimes(2); + expect(onButtonQuestionLostFocusCallbackTwo).toHaveBeenCalledTimes(1); + }); +}); From 78bb3f5e8c07dd5d3a4277e14a9c7a10156e9da7 Mon Sep 17 00:00:00 2001 From: Katie Date: Thu, 20 Oct 2022 12:36:45 -0400 Subject: [PATCH 6/9] CSR-762 tests --- .../base-input-button.spec.js | 284 ++-------- .../base-input-button/base-input-button.vue | 1 - .../button-question/button-question.spec.js | 277 ++++----- src/helpers/button-question-focus-helper.js | 1 - .../vehicle-parts/vehicle-parts.spec.js | 2 +- src/mixins/input-button-wrapper-mixin.spec.js | 259 +++++++-- .../list-button-horizontal.spec.js | 374 +++++++------ .../list-button/list-button.spec.js | 527 ++++++++++-------- src/ux-components/list-button/list-button.vue | 1 + 9 files changed, 856 insertions(+), 870 deletions(-) diff --git a/src/common-components/base-input-button/base-input-button.spec.js b/src/common-components/base-input-button/base-input-button.spec.js index 75982cf73..273f3d491 100644 --- a/src/common-components/base-input-button/base-input-button.spec.js +++ b/src/common-components/base-input-button/base-input-button.spec.js @@ -1,8 +1,6 @@ import { shallowMount, mount } from "@vue/test-utils"; import baseInputButton from "./base-input-button"; -import inputButtonWrapperMixin from "@/mixins/input-button-wrapper-mixin"; -// TODO KO describe("baseInputButton.vue", () => { describe("general", () => { describe("checkbox", () => { @@ -73,14 +71,14 @@ describe("baseInputButton.vue", () => { }, }, }); - + // Act await wrapper.trigger("click"); - + // Assert expect(wrapper.emitted()["update:modelValue"][0][0]).toEqual(["X"]); }); - + test("input is checked", async () => { // Arrange const { wrapper } = setupMocks({ @@ -92,17 +90,16 @@ describe("baseInputButton.vue", () => { }, }); const input = wrapper.find("input"); - + // Act await wrapper.trigger("click"); - - + // Assert expect(input.element.checked).toBe(true); }); - }) - - describe("clicked twice" ,() => { + }); + + describe("clicked twice", () => { test("input is unchecked", async () => { // Arrange const { wrapper } = setupMocks({ @@ -114,15 +111,15 @@ describe("baseInputButton.vue", () => { }, }); const input = wrapper.find("input"); - + // Act await wrapper.trigger("click"); await wrapper.trigger("click"); - + // Assert expect(input.element.checked).toBe(false); }); - }) + }); describe("is initially checked, click once", () => { test("input is unchecked", async () => { @@ -132,19 +129,19 @@ describe("baseInputButton.vue", () => { propsData: { isMultiSelect: true, value: "X", - modelValue:["X"] + modelValue: ["X"], }, }, }); const input = wrapper.find("input"); - + // Act await wrapper.trigger("click"); - + // Assert expect(input.element.checked).toBe(false); }); - + test("input is unchecked", async () => { // Arrange const { wrapper } = setupMocks({ @@ -152,19 +149,19 @@ describe("baseInputButton.vue", () => { propsData: { isMultiSelect: true, value: "X", - modelValue:["X"] + modelValue: ["X"], }, }, }); const input = wrapper.find("input"); - + // Act await wrapper.trigger("click"); - + // Assert expect(input.element.checked).toBe(false); }); - }) + }); }); describe("radio", () => { @@ -189,12 +186,8 @@ describe("baseInputButton.vue", () => { }); }); - describe("keyboard navigation and events", () => { + describe("events", () => { describe("checkbox", () => { - test.todo("focus on a checkbox => update:modelValue is not emitted"); - - test.todo("blur from a checkbox => update:modelValue is not emitted"); - test("change event fired from checkbox => update:modelValue is emitted with correct value", async () => { // Arrange const { wrapper } = setupMocks({ @@ -257,10 +250,6 @@ describe("baseInputButton.vue", () => { }); describe("radio", () => { - test.todo("focus on a radio button => update:modelValue is not emitted"); - - test.todo("blur from a radio button => update:modelValue is not emitted"); - test("focus and click space on a radio button => update:modelValue is emitted with correct value", async () => { // Arrange const { wrapper } = setupMocks({ @@ -775,7 +764,19 @@ describe("baseInputButton.vue", () => { }); describe("handlePushClickEventToGACheck", () => { - test.todo(""); + test.todo("called from click or click-like event => call pushClickEventToGA"); + + describe("called from keyboard navigation/button-question-focus-helper", () => { + test.todo("valueToEmit is null => pushClickEventToGA not called"); + + test.todo("isMultiSelect => pushClickEventToGA not called"); + + test.todo("!isMultiSelect and selectingInitiatesLoad => pushClickEventToGA not called"); + + test.todo("valueToEmit is null => pushClickEventToGA not called"); + + test.todo("valueToEmit is null => pushClickEventToGA not called"); + }); }); describe("pushClickEventToGA", () => { @@ -1011,179 +1012,17 @@ describe("baseInputButton.vue", () => { }); }); - describe("integration testing", () => { + describe("keyboard navigation", () => { describe("checkbox", () => { - test("click on both => both are selected", async () => { - // Arrange - const { wrapper } = setupBaseInputButtonWrapper({ - mockData: { - isMultiSelect: true, - }, - }); + test.todo("focus on a checkbox => update:modelValue is not emitted"); - // Act - const buttonWrappers = wrapper.findAllComponents({ - name: "baseInputButtonWrapper", - }); - const inputButtonOne = buttonWrappers.at(0); - const inputButtonTwo = buttonWrappers.at(1); - expect(inputButtonOne.vm.isMultiSelect).toBe(true); - expect(inputButtonTwo.vm.isMultiSelect).toBe(true); - expect(wrapper.vm.value).toEqual([]); - - await inputButtonOne.find("input").trigger("click"); - await inputButtonTwo.find("input").trigger("click"); - - // Assert - expect(wrapper.vm.value).toEqual(["value1", "value2"]); - }); - - test("click input 1, 2, 1 => only input 2 selected", async () => { - // Arrange - const { wrapper } = setupBaseInputButtonWrapper({ - mockData: { - isMultiSelect: true, - }, - }); - - // Act - const buttonWrappers = wrapper.findAllComponents({ - name: "baseInputButtonWrapper", - }); - const inputButtonOne = buttonWrappers.at(0); - const inputButtonTwo = buttonWrappers.at(1); - expect(inputButtonOne.vm.isMultiSelect).toBe(true); - expect(inputButtonTwo.vm.isMultiSelect).toBe(true); - expect(wrapper.vm.value).toEqual([]); - - await inputButtonOne.find("input").trigger("click"); - await inputButtonTwo.find("input").trigger("click"); - await inputButtonOne.find("input").trigger("click"); - - // Assert - expect(wrapper.vm.value).toEqual(["value2"]); - }); - - const defaultCheckedCases = [ - [["value2"], false, true], - [["value1", "value2"], true, true], - [["value1"], true, false], - [[], false, false], - ]; - test.each(defaultCheckedCases)( - "initial value is %s => correct input buttons are selected", - async (modelValue, isInputButtonOneChecked, isInputButtonTwoChecked) => { - // Arrange - const { wrapper } = setupBaseInputButtonWrapper({ - mockData: { - isMultiSelect: true, - initialValue: modelValue, - }, - }); - - // Act - const buttonWrappers = wrapper.findAllComponents({ - name: "baseInputButtonWrapper", - }); - const inputs = wrapper.findAll("input"); - const inputButtonOne = buttonWrappers.at(0); - const inputButtonTwo = buttonWrappers.at(1); - - // Assert - expect(inputButtonOne.vm.isMultiSelect).toBe(true); - expect(inputButtonTwo.vm.isMultiSelect).toBe(true); - expect(inputs[0].element.checked).toBe(isInputButtonOneChecked); - expect(inputs[1].element.checked).toBe(isInputButtonTwoChecked); - expect(wrapper.vm.value).toEqual(modelValue); - } - ); + test.todo("blur from a checkbox => update:modelValue is not emitted"); }); describe("radio", () => { - test("click on both => last clicked is selected", async () => { - // Arrange - const { wrapper } = setupBaseInputButtonWrapper({ - mockData: { - isMultiSelect: false, - }, - }); + test.todo("focus on a radio button => update:modelValue is not emitted"); - // Act - const buttonWrappers = wrapper.findAllComponents({ - name: "baseInputButtonWrapper", - }); - const inputButtonOne = buttonWrappers.at(0); - const inputButtonTwo = buttonWrappers.at(1); - expect(inputButtonOne.vm.isMultiSelect).toBe(false); - expect(inputButtonTwo.vm.isMultiSelect).toBe(false); - expect(wrapper.vm.value).toEqual(""); - - await inputButtonOne.find("input").trigger("click"); - await inputButtonTwo.find("input").trigger("click"); - - // Assert - expect(wrapper.vm.value).toEqual("value2"); - }); - - test("click input 1, 2, 1 => input 1 is selected", async () => { - // Arrange - const { wrapper } = setupBaseInputButtonWrapper({ - mockData: { - isMultiSelect: false, - }, - }); - - // Act - const buttonWrappers = wrapper.findAllComponents({ - name: "baseInputButtonWrapper", - }); - const inputButtonOne = buttonWrappers.at(0); - const inputButtonTwo = buttonWrappers.at(1); - expect(inputButtonOne.vm.isMultiSelect).toBe(false); - expect(inputButtonTwo.vm.isMultiSelect).toBe(false); - expect(wrapper.vm.value).toEqual(""); - - await inputButtonOne.find("input").trigger("click"); - await inputButtonTwo.find("input").trigger("click"); - await inputButtonOne.find("input").trigger("click"); - - // Assert - expect(wrapper.vm.value).toEqual("value1"); - }); - - const defaultCheckedCases = [ - ["", false, false], - ["value1", true, false], - ["value2", false, true], - [[], false, false], - ]; - test.each(defaultCheckedCases)( - "initial value is %s => correct input buttons are selected", - async (modelValue, isInputButtonOneChecked, isInputButtonTwoChecked) => { - // Arrange - const { wrapper } = setupBaseInputButtonWrapper({ - mockData: { - isMultiSelect: false, - initialValue: modelValue, - }, - }); - - // Act - const buttonWrappers = wrapper.findAllComponents({ - name: "baseInputButtonWrapper", - }); - const inputs = wrapper.findAll("input"); - const inputButtonOne = buttonWrappers.at(0); - const inputButtonTwo = buttonWrappers.at(1); - - // Assert - expect(inputButtonOne.vm.isMultiSelect).toBe(false); - expect(inputButtonTwo.vm.isMultiSelect).toBe(false); - expect(inputs[0].element.checked).toBe(isInputButtonOneChecked); - expect(inputs[1].element.checked).toBe(isInputButtonTwoChecked); - expect(wrapper.vm.value).toEqual(modelValue); - } - ); + test.todo("blur from a radio button => update:modelValue is not emitted"); }); }); }); @@ -1216,50 +1055,3 @@ function setupMocks({ mockData = {}, shouldShallowMount = true }) { return { wrapper }; } - -function setupBaseInputButtonWrapper({ mockData = {} }) { - const originalData = baseInputButton.data(); - baseInputButton.data = () => { - return { - ...originalData, - // $route: { - // query: { - // fmgPage: "myPage", - // }, - // }, - }; - }; - - baseInputButton.methods.pushClickEventToGA = jest.fn(); - - const baseInputButtonWrapper = { - name: "baseInputButtonWrapper", - components: { baseInputButton }, - template: '
', - mixins: [inputButtonWrapperMixin], - }; - - let parentComponentTemplate = `
`; - parentComponentTemplate += ``; - parentComponentTemplate += ``; - parentComponentTemplate += `
`; - const wrapper = mount( - { - data() { - return { - value: mockData.initialValue ?? (mockData.isMultiSelect ? [] : ""), - $route: { - query: { - fmgPage: "myPage", - }, - }, - }; - }, - template: parentComponentTemplate, - components: { baseInputButtonWrapper }, - }, - {} - ); - - return { wrapper }; -} diff --git a/src/common-components/base-input-button/base-input-button.vue b/src/common-components/base-input-button/base-input-button.vue index 3f4fd4c2c..c01a9a94c 100644 --- a/src/common-components/base-input-button/base-input-button.vue +++ b/src/common-components/base-input-button/base-input-button.vue @@ -97,7 +97,6 @@ export default { }, handleClick(e) { this.handleSelectionChange(e); - console.log(this.valueToEmit) this.$emit("update:modelValue", this.valueToEmit); }, handleFocus() { diff --git a/src/common-components/button-question/button-question.spec.js b/src/common-components/button-question/button-question.spec.js index 2e732d881..0e51949a8 100644 --- a/src/common-components/button-question/button-question.spec.js +++ b/src/common-components/button-question/button-question.spec.js @@ -3,171 +3,172 @@ import buttonQuestion from "@/common-components/button-question/button-question" import { getMountOptions } from "@/helpers/unit-test-helper.js"; jest.mock( - "@/store", - () => { - return {}; - }, - { virtual: true } + "@/store", + () => { + return {}; + }, + { virtual: true } ); describe("buttonQuestion.vue", () => { - it("Should show overflow classes on fieldset if isOverflowScrollable is true", () => { - // Act - const wrapper = shallowMount(buttonQuestion, { - propsData: { - isOverflowScrollable: true, - groupName: "group-name", - }, - }); + it("Should show overflow classes on fieldset if isOverflowScrollable is true", () => { + // Act + const wrapper = shallowMount(buttonQuestion, { + propsData: { + isOverflowScrollable: true, + groupName: "group-name", + }, + }); - // Assert - const fieldSet = wrapper.find("fieldset"); - expect(fieldSet.classes()).toContain("overflow-scroll"); - }); + // Assert + const fieldSet = wrapper.find("fieldset"); + expect(fieldSet.classes()).toContain("overflow-scroll"); + }); }); describe("buttonQuestion.vue", () => { - it("Fieldset classes should contain row if button type is listCard", () => { - // Act - const wrapper = shallowMount(buttonQuestion, { - propsData: { - buttonType: "listCard", - groupName: "group-name", - }, + it("Fieldset classes should contain row if button type is listCard", () => { + // Act + const wrapper = shallowMount(buttonQuestion, { + propsData: { + buttonType: "listCard", + groupName: "group-name", + }, + }); + // Assert + const Div = wrapper.find("fieldset div"); + expect(Div.classes()).toContain("row"); }); - // Assert - const Div = wrapper.find("fieldset div"); - expect(Div.classes()).toContain("row"); - }); }); describe("buttonQuestion.vue", () => { - it("Fieldset classes should contain d-flex if button type is listButtonHorizontal", () => { - // Act - const wrapper = shallowMount(buttonQuestion, { - propsData: { - buttonType: "listButtonHorizontal", - groupName: "group-name", - }, + it("Fieldset classes should contain d-flex if button type is listButtonHorizontal", () => { + // Act + const wrapper = shallowMount(buttonQuestion, { + propsData: { + buttonType: "listButtonHorizontal", + groupName: "group-name", + }, + }); + // Assert + const Div = wrapper.find("fieldset div"); + expect(Div.classes()).toContain("d-flex"); }); - // Assert - const Div = wrapper.find("fieldset div"); - expect(Div.classes()).toContain("d-flex"); - }); }); describe("buttonQuestion.vue", () => { - it("Fieldset classes should contain ui-radio if button type is radio", () => { - // Act - const wrapper = shallowMount(buttonQuestion, { - propsData: { - buttonType: "radio", - groupName: "group-name", - }, + it("Fieldset classes should contain ui-radio if button type is radio", () => { + // Act + const wrapper = shallowMount(buttonQuestion, { + propsData: { + buttonType: "radio", + groupName: "group-name", + }, + }); + // Assert + const Div = wrapper.find("fieldset div"); + expect(Div.classes()).toContain("ui-radio"); }); - // Assert - const Div = wrapper.find("fieldset div"); - expect(Div.classes()).toContain("ui-radio"); - }); }); // testing a computed property describe("buttonQuestion.vue", () => { - it("getColLength should return '12' if prop isWide is set to true", () => { - // Act - const localThis = { isWide: true }; + 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", - }; - - expect(buttonQuestion.computed.getColLength.call(localThis)).toBe(""); - }); -}); - -describe("buttonQuestion.vue", () => { - it("Should return answer.Text if prop useTextForValue is true", async () => { - // Act - const localThis = { useTextForValue: true }; - const answer = { Name: "testName", Text: "testText" }; - - // Assert - expect(buttonQuestion.methods.getValue.call(localThis, answer)).toBe( - "testText" - ); - }); -}); - -describe("buttonQuestion.vue", () => { - it("Should return answer.Name if prop useTextForValue is false and there's not buttonLabel and answer.Name exists", async () => { - // Act - const localThis = { useTextForValue: false }; - const answer = { Name: "testName", Text: "testText" }; - - // Assert - expect(buttonQuestion.methods.getValue.call(localThis, answer)).toBe( - "testName" - ); - }); -}); - -// TODO KO -describe("buttonQuestion.vue", () => { - describe.skip("handleAnswerChange", () => { - test("is radio => should emit captured value", async () => { - // Act - const wrapper = shallowMount( - buttonQuestion, - setupMocks({ propsData: { groupName: "group-name" } }) - ); - await wrapper.setProps({ - answers: ["2022", "2021", "2020"], - isMultiSelect: false, - modelValue: "", - }); - const val = "2021"; - wrapper.vm.handleAnswerChange(val); - - // Assert - expect(wrapper.emitted()["update:modelValue"][0]).toEqual(["2021"]); + expect(buttonQuestion.computed.getColLength.call(localThis)).toBe("12"); }); +}); - test("is checkbox => should emit captured value", async () => { - const wrapper = shallowMount( - buttonQuestion, - setupMocks({ propsData: { groupName: "group-name" } }) - ); - await wrapper.setProps({ - answers: ["2022", "2021", "2020"], - isMultiSelect: false, - modelValue: "", - }); - const val = ["2022", "2021", , "2019", "2020"]; - wrapper.vm.handleAnswerChange(val); +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", + }; - // Assert - expect(wrapper.emitted()["update:modelValue"][0]).toEqual([ - ["2022", "2021", , "2019", "2020"], - ]); + expect(buttonQuestion.computed.getColLength.call(localThis)).toBe(""); + }); +}); + +describe("buttonQuestion.vue", () => { + it("Should return answer.Text if prop useTextForValue is true", async () => { + // Act + const localThis = { useTextForValue: true }; + const answer = { Name: "testName", Text: "testText" }; + + // Assert + expect(buttonQuestion.methods.getValue.call(localThis, answer)).toBe("testText"); + }); +}); + +describe("buttonQuestion.vue", () => { + it("Should return answer.Name if prop useTextForValue is false and there's not buttonLabel and answer.Name exists", async () => { + // Act + const localThis = { useTextForValue: false }; + const answer = { Name: "testName", Text: "testText" }; + + // Assert + expect(buttonQuestion.methods.getValue.call(localThis, answer)).toBe("testName"); + }); +}); + +describe("buttonQuestion.vue", () => { + describe("selectedValues", () => { + test("is radio => should emit captured value", async () => { + // Arrange + const wrapper = shallowMount( + buttonQuestion, + setupMocks({ propsData: { groupName: "group-name" } }) + ); + await wrapper.setProps({ + answers: ["2022", "2021", "2020"], + isMultiSelect: false, + modelValue: "", + }); + + // Act + wrapper.vm.selectedValues = "2021"; + + // Assert + expect(wrapper.emitted()["update:modelValue"][0][0]).toEqual("2021"); + }); + + test("is checkbox => should emit captured value", async () => { + const wrapper = shallowMount( + buttonQuestion, + setupMocks({ propsData: { groupName: "group-name" } }) + ); + await wrapper.setProps({ + answers: ["2022", "2021", "2020"], + isMultiSelect: false, + modelValue: "", + }); + + // Act + wrapper.vm.selectedValues = ["2022", "2021", "2020", "2019", "2020"]; + + // Assert + expect(wrapper.emitted()["update:modelValue"][0][0]).toEqual([ + "2022", + "2021", + "2020", + "2019", + "2020", + ]); + }); }); - }); }); function setupMocks(mountOptionsMockData = {}) { - const defaultMountOptions = { route: { query: { fmgPage: "page-name" } } }; - const baseMountOptions = getMountOptions( - Object.assign(defaultMountOptions, mountOptionsMockData) - ); - const allMountOptions = Object.assign(defaultMountOptions, baseMountOptions); + const defaultMountOptions = { route: { query: { fmgPage: "page-name" } } }; + const baseMountOptions = getMountOptions( + Object.assign(defaultMountOptions, mountOptionsMockData) + ); + const allMountOptions = Object.assign(defaultMountOptions, baseMountOptions); - return allMountOptions; + return allMountOptions; } diff --git a/src/helpers/button-question-focus-helper.js b/src/helpers/button-question-focus-helper.js index 9884fa041..f2aac0ba5 100644 --- a/src/helpers/button-question-focus-helper.js +++ b/src/helpers/button-question-focus-helper.js @@ -8,7 +8,6 @@ let lastFocusedInputGroupName = ""; let onButtonQuestionLostFocusCallback = null; -// TODO KO add tests const handleAnyComponentFocus = (e) => { const targetType = e.target.type; if (targetType !== "radio" && targetType !== "checkbox") { diff --git a/src/layouts/vehicle-parts/vehicle-parts.spec.js b/src/layouts/vehicle-parts/vehicle-parts.spec.js index 7e6fe9130..df45f7867 100644 --- a/src/layouts/vehicle-parts/vehicle-parts.spec.js +++ b/src/layouts/vehicle-parts/vehicle-parts.spec.js @@ -148,7 +148,7 @@ describe("vehicle-parts.vue", () => { expect(arePagePrerequisitesValid).toBe(true); }); - test.only("Initial data, should populate this.selectedGlassParts", async () => { + test("Initial data, should populate this.selectedGlassParts", async () => { //Arrange store.getters.pageData.mockReturnValue(basePartResponse); diff --git a/src/mixins/input-button-wrapper-mixin.spec.js b/src/mixins/input-button-wrapper-mixin.spec.js index 8f03de0aa..8724a5dd9 100644 --- a/src/mixins/input-button-wrapper-mixin.spec.js +++ b/src/mixins/input-button-wrapper-mixin.spec.js @@ -1,81 +1,234 @@ +import { mount } from "@vue/test-utils"; +import baseInputButton from "@/common-components/base-input-button/base-input-button"; +import inputButtonWrapperMixin from "@/mixins/input-button-wrapper-mixin"; + describe("input-button-wrapper-mixin", () => { describe("mouse clicks", () => { describe("checkbox", () => { - test.todo("clicking once checks the baseInputButton"); + test("click on both => both are selected", async () => { + // Arrange + const { wrapper } = setupBaseInputButtonWrapper({ + mockData: { + isMultiSelect: true, + }, + }); - test.todo("clicking twice unchecks the baseInputButton"); + // Act + const buttonWrappers = wrapper.findAllComponents({ + name: "baseInputButtonWrapper", + }); + const inputButtonOne = buttonWrappers.at(0); + const inputButtonTwo = buttonWrappers.at(1); + expect(inputButtonOne.vm.isMultiSelect).toBe(true); + expect(inputButtonTwo.vm.isMultiSelect).toBe(true); + expect(wrapper.vm.value).toEqual([]); - test.todo( - "is initially checked => checking unchecks the baseInputButton" - ); + await inputButtonOne.find("input").trigger("click"); + await inputButtonTwo.find("input").trigger("click"); - test.todo("clicked => correct event and value are emitted"); + // Assert + expect(wrapper.vm.value).toEqual(["value1", "value2"]); + }); + + test("click input 1, 2, 1 => only input 2 selected", async () => { + // Arrange + const { wrapper } = setupBaseInputButtonWrapper({ + mockData: { + isMultiSelect: true, + }, + }); + + // Act + const buttonWrappers = wrapper.findAllComponents({ + name: "baseInputButtonWrapper", + }); + const inputButtonOne = buttonWrappers.at(0); + const inputButtonTwo = buttonWrappers.at(1); + expect(inputButtonOne.vm.isMultiSelect).toBe(true); + expect(inputButtonTwo.vm.isMultiSelect).toBe(true); + expect(wrapper.vm.value).toEqual([]); + + await inputButtonOne.find("input").trigger("click"); + await inputButtonTwo.find("input").trigger("click"); + await inputButtonOne.find("input").trigger("click"); + + // Assert + expect(wrapper.vm.value).toEqual(["value2"]); + }); }); describe("radio", () => { - test.todo("clicking once selects the baseInputButton"); + test("click on both => last clicked is selected", async () => { + // Arrange + const { wrapper } = setupBaseInputButtonWrapper({ + mockData: { + isMultiSelect: false, + }, + }); - test.todo("clicking twice keeps the baseInputButton selected"); + // Act + const buttonWrappers = wrapper.findAllComponents({ + name: "baseInputButtonWrapper", + }); + const inputButtonOne = buttonWrappers.at(0); + const inputButtonTwo = buttonWrappers.at(1); + expect(inputButtonOne.vm.isMultiSelect).toBe(false); + expect(inputButtonTwo.vm.isMultiSelect).toBe(false); + expect(wrapper.vm.value).toEqual(""); - test.todo( - "is initially selected => click keeps the baseInputButton selected" - ); + await inputButtonOne.find("input").trigger("click"); + await inputButtonTwo.find("input").trigger("click"); - test.todo("clicked => correct event and value are emitted"); + // Assert + expect(wrapper.vm.value).toEqual("value2"); + }); + + test("click input 1, 2, 1 => input 1 is selected", async () => { + // Arrange + const { wrapper } = setupBaseInputButtonWrapper({ + mockData: { + isMultiSelect: false, + }, + }); + + // Act + const buttonWrappers = wrapper.findAllComponents({ + name: "baseInputButtonWrapper", + }); + const inputButtonOne = buttonWrappers.at(0); + const inputButtonTwo = buttonWrappers.at(1); + expect(inputButtonOne.vm.isMultiSelect).toBe(false); + expect(inputButtonTwo.vm.isMultiSelect).toBe(false); + expect(wrapper.vm.value).toEqual(""); + + await inputButtonOne.find("input").trigger("click"); + await inputButtonTwo.find("input").trigger("click"); + await inputButtonOne.find("input").trigger("click"); + + // Assert + expect(wrapper.vm.value).toEqual("value1"); + }); }); }); - describe("keyboard navigation and", () => { + describe("initial values", () => { describe("checkbox", () => { - test.todo( - "focus on a checkbox => inputButtonClicked is not emitted" - ); + const defaultCheckedCases = [ + [["value2"], false, true], + [["value1", "value2"], true, true], + [["value1"], true, false], + [[], false, false], + ]; + test.each(defaultCheckedCases)( + "initial value is %s => correct input buttons are selected", + async (modelValue, isInputButtonOneChecked, isInputButtonTwoChecked) => { + // Arrange + const { wrapper } = setupBaseInputButtonWrapper({ + mockData: { + isMultiSelect: true, + initialValue: modelValue, + }, + }); - test.todo( - "blur from a checkbox => inputButtonClicked is not emitted" - ); + // Act + const buttonWrappers = wrapper.findAllComponents({ + name: "baseInputButtonWrapper", + }); + const inputs = wrapper.findAll("input"); + const inputButtonOne = buttonWrappers.at(0); + const inputButtonTwo = buttonWrappers.at(1); - 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" + // Assert + expect(inputButtonOne.vm.isMultiSelect).toBe(true); + expect(inputButtonTwo.vm.isMultiSelect).toBe(true); + expect(inputs[0].element.checked).toBe(isInputButtonOneChecked); + expect(inputs[1].element.checked).toBe(isInputButtonTwoChecked); + expect(wrapper.vm.value).toEqual(modelValue); + } ); }); describe("radio", () => { - test.todo( - "focus on a radio button => inputButtonClicked is not emitted" - ); + const defaultCheckedCases = [ + ["", false, false], + ["value1", true, false], + ["value2", false, true], + [[], false, false], + ]; + test.each(defaultCheckedCases)( + "initial value is %s => correct input buttons are selected", + async (modelValue, isInputButtonOneChecked, isInputButtonTwoChecked) => { + // Arrange + const { wrapper } = setupBaseInputButtonWrapper({ + mockData: { + isMultiSelect: false, + initialValue: modelValue, + }, + }); - test.todo( - "blur from a radio button => inputButtonClicked is not emitted" - ); + // Act + const buttonWrappers = wrapper.findAllComponents({ + name: "baseInputButtonWrapper", + }); + const inputs = wrapper.findAll("input"); + const inputButtonOne = buttonWrappers.at(0); + const inputButtonTwo = buttonWrappers.at(1); - 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" + // Assert + expect(inputButtonOne.vm.isMultiSelect).toBe(false); + expect(inputButtonTwo.vm.isMultiSelect).toBe(false); + expect(inputs[0].element.checked).toBe(isInputButtonOneChecked); + expect(inputs[1].element.checked).toBe(isInputButtonTwoChecked); + expect(wrapper.vm.value).toEqual(modelValue); + } ); }); }); }); + +function setupBaseInputButtonWrapper({ mockData = {} }) { + const originalData = baseInputButton.data(); + baseInputButton.data = () => { + return { + ...originalData, + // $route: { + // query: { + // fmgPage: "myPage", + // }, + // }, + }; + }; + + baseInputButton.methods.pushClickEventToGA = jest.fn(); + + const baseInputButtonWrapper = { + name: "baseInputButtonWrapper", + components: { baseInputButton }, + template: '
', + mixins: [inputButtonWrapperMixin], + }; + + let parentComponentTemplate = `
`; + parentComponentTemplate += ``; + parentComponentTemplate += ``; + parentComponentTemplate += `
`; + const wrapper = mount( + { + data() { + return { + value: mockData.initialValue ?? (mockData.isMultiSelect ? [] : ""), + $route: { + query: { + fmgPage: "myPage", + }, + }, + }; + }, + template: parentComponentTemplate, + components: { baseInputButtonWrapper }, + }, + {} + ); + + return { wrapper }; +} diff --git a/src/ux-components/list-button-horizontal/list-button-horizontal.spec.js b/src/ux-components/list-button-horizontal/list-button-horizontal.spec.js index 6817ec8c5..e101e5fc0 100644 --- a/src/ux-components/list-button-horizontal/list-button-horizontal.spec.js +++ b/src/ux-components/list-button-horizontal/list-button-horizontal.spec.js @@ -1,202 +1,200 @@ -import { shallowMount, mount } from "@vue/test-utils"; +import { mount } from "@vue/test-utils"; import listButtonHorizontal from "./list-button-horizontal"; -import { nextTick } from "vue"; -import { GaActions } from "@/constants/analytics"; import inputButtonWrapperMixin from "@/mixins/input-button-wrapper-mixin"; describe("list-button-horizontal.vue", () => { - // TODO KO Have this moved out to somewhere shared - describe("Shared baseInputButton checks", () => { - it("Should return input type checkbox if isMultiSelect is true", async () => { - // Act - const { wrapper } = setupMocks({ - mockData: { - propsData: { - isMultiSelect: true, - }, - }, - }); + // TODO KO Have this moved out to somewhere shared + describe("Shared baseInputButton checks", () => { + it("Should return input type checkbox if isMultiSelect is true", async () => { + // Act + const { wrapper } = setupMocks({ + mockData: { + propsData: { + isMultiSelect: true, + }, + }, + }); - // Assert - const input = wrapper.find("input"); - expect(input.attributes().type).toEqual("checkbox"); + // Assert + const input = wrapper.find("input"); + expect(input.attributes().type).toEqual("checkbox"); + }); + + it("Should return input type radio if isMultiSelect is false or not specified", async () => { + // Act + const { wrapper } = setupMocks({ + mockData: { + propsData: { + isMultiSelect: false, + }, + }, + }); + + // Assert + const input = wrapper.find("input"); + expect(input.attributes().type).toEqual("radio"); + }); + + const selectedValues = ["something", ["test"]] + it.each(selectedValues)("Should emit button value on click", async (selectedValue) => { + // Act + const { wrapper } = setupMocks({ + mockData: { + propsData: { + isRadioHorizontal: true, + buttonLabel: "Windshield", + value: "List Card Checkbox", + groupID: "radio-demo-1", + groupName: "radio 1", + buttonImage: "windshield-damage.svg", + isRequired: true, + isWide: false, + modelValue: ["List Card Checkbox"], + buttonID: "list-card-id", + }, + }, + }); + + // Act + wrapper.vm.selectedValue = selectedValue; + await wrapper.vm.$nextTick(); + + // Assert + expect(wrapper.emitted()["update:modelValue"][0][0]).toEqual(selectedValue); + }); }); - it("Should return input type radio if isMultiSelect is false or not specified", async () => { - // Act - const { wrapper } = setupMocks({ - mockData: { - propsData: { - isMultiSelect: false, - }, - }, - }); + describe("styling/UI", () => { + it("Should return screen reader text", async () => { + // Act + const { wrapper } = setupMocks({ + mockData: { + propsData: { + screenReaderOnlyText: "Screen Reader Only Text", + }, + }, + }); - // Assert - const input = wrapper.find("input"); - expect(input.attributes().type).toEqual("radio"); + // Assert + const paragraph = wrapper.find("span.sr-only"); + + expect(paragraph.text()).toEqual("Screen Reader Only Text"); + }); + + it("Should return text alignment class", async () => { + // Act + const { wrapper } = setupMocks({ + mockData: { + propsData: { + textPosition: "text-center", + }, + }, + }); + + // Assert + const paragraph = wrapper.find("span.m-0"); + + expect(paragraph.attributes("class")).toContain("text-center"); + }); + + it("Should return aria-required state", async () => { + // Act + const { wrapper } = setupMocks({ + mockData: { + propsData: { + isRequired: true, + }, + }, + }); + + // Assert + const input = wrapper.find("input"); + + expect(input.attributes()["aria-required"]).toEqual("true"); + }); + + it("is cash or insurance button => has 'radio-fancy' class", () => { + // Arrange/Act + const { wrapper } = setupMocks({ + mockData: { + propsData: { + isCashOrInsurance: true, + }, + }, + }); + + // Assert + const label = wrapper.find("label"); + + expect(label.classes()).toContain("radio-fancy"); + }); + + test("has buttonLabel => displays buttonLabel", () => { + // Arrange/Act + const { wrapper } = setupMocks({ + mockData: { + propsData: { + buttonLabel: "Surprise!", + }, + }, + }); + + // Assert + const content = wrapper.find(".list-button-horizontal-content"); + expect(content.isVisible()).toBe(true); + expect(content.text()).toContain("Surprise!"); + }); + + test("has buttonLabelSubCopy => displays buttonLabelSubCopy", () => { + // Arrange/Act + const { wrapper } = setupMocks({ + mockData: { + propsData: { + buttonLabel: "Surprise!", + buttonLabelSubCopy: "Super duper surprise :)", + }, + }, + }); + + // Assert + const content = wrapper.find(".list-button-horizontal-content"); + expect(content.isVisible()).toBe(true); + expect(content.text()).toContain("Super duper surprise :)"); + }); + + test("has screenReaderOnlyText => displays screenReaderOnlyText", () => { + // Arrange/Act + const { wrapper } = setupMocks({ + mockData: { + propsData: { + buttonLabel: "Surprise!", + buttonLabelSubCopy: "Super duper surprise :)", + screenReaderOnlyText: "Tests are fun!", + }, + }, + }); + + // Assert + const content = wrapper.find(".list-button-horizontal-content"); + const screenReaderOnlyText = wrapper.find(".sr-only"); + expect(content.isVisible()).toBe(true); + expect(screenReaderOnlyText.exists()).toBe(true); + expect(screenReaderOnlyText.text()).toContain("Tests are fun!"); + }); }); - - // TODO KO - it.skip("Should emit button value on click", async () => { - // Act - const { wrapper } = setupMocks({ - mockData: { - propsData: { - isRadioHorizontal: true, - buttonLabel: "Windshield", - value: "List Card Checkbox", - groupID: "radio-demo-1", - groupName: "radio 1", - buttonImage: "windshield-damage.svg", - isRequired: true, - isWide: false, - modelValue: ["List Card Checkbox"], - buttonID: "list-card-id", - }, - }, - }); - - // Act - wrapper.vm.handleAnswerChange("test"); - await wrapper.vm.$nextTick(); - - // Assert - expect(wrapper.emitted()["change"][0]).toEqual(["test"]); - }); - }); - - describe("styling/UI", () => { - it("Should return screen reader text", async () => { - // Act - const { wrapper } = setupMocks({ - mockData: { - propsData: { - screenReaderOnlyText: "Screen Reader Only Text", - }, - }, - }); - - // Assert - const paragraph = wrapper.find("span.sr-only"); - - expect(paragraph.text()).toEqual("Screen Reader Only Text"); - }); - - it("Should return text alignment class", async () => { - // Act - const { wrapper } = setupMocks({ - mockData: { - propsData: { - textPosition: "text-center", - }, - }, - }); - - // Assert - const paragraph = wrapper.find("span.m-0"); - - expect(paragraph.attributes("class")).toContain("text-center"); - }); - - it("Should return aria-required state", async () => { - // Act - const { wrapper } = setupMocks({ - mockData: { - propsData: { - isRequired: true, - }, - }, - }); - - // Assert - const input = wrapper.find("input"); - - expect(input.attributes()["aria-required"]).toEqual("true"); - }); - - it("is cash or insurance button => has 'radio-fancy' class", () => { - // Arrange/Act - const { wrapper } = setupMocks({ - mockData: { - propsData: { - isCashOrInsurance: true, - }, - }, - }); - - // Assert - const label = wrapper.find("label"); - - expect(label.classes()).toContain("radio-fancy"); - }); - - test("has buttonLabel => displays buttonLabel", () => { - // Arrange/Act - const { wrapper } = setupMocks({ - mockData: { - propsData: { - buttonLabel: "Surprise!", - }, - }, - }); - - // Assert - const content = wrapper.find(".list-button-horizontal-content"); - expect(content.isVisible()).toBe(true); - expect(content.text()).toContain("Surprise!"); - }); - - test("has buttonLabelSubCopy => displays buttonLabelSubCopy", () => { - // Arrange/Act - const { wrapper } = setupMocks({ - mockData: { - propsData: { - buttonLabel: "Surprise!", - buttonLabelSubCopy: "Super duper surprise :)", - }, - }, - }); - - // Assert - const content = wrapper.find(".list-button-horizontal-content"); - expect(content.isVisible()).toBe(true); - expect(content.text()).toContain("Super duper surprise :)"); - }); - - test("has screenReaderOnlyText => displays screenReaderOnlyText", () => { - // Arrange/Act - const { wrapper } = setupMocks({ - mockData: { - propsData: { - buttonLabel: "Surprise!", - buttonLabelSubCopy: "Super duper surprise :)", - screenReaderOnlyText: "Tests are fun!" - }, - }, - }); - - // Assert - const content = wrapper.find(".list-button-horizontal-content"); - const screenReaderOnlyText = wrapper.find(".sr-only"); - expect(content.isVisible()).toBe(true); - expect(screenReaderOnlyText.exists()).toBe(true); - expect(screenReaderOnlyText.text()).toContain("Tests are fun!"); - }); - }); }); function setupMocks({ mockData }) { - 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], - }); + 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 }; + return { wrapper }; } diff --git a/src/ux-components/list-button/list-button.spec.js b/src/ux-components/list-button/list-button.spec.js index 21c1a37b4..d932b1ea3 100644 --- a/src/ux-components/list-button/list-button.spec.js +++ b/src/ux-components/list-button/list-button.spec.js @@ -1,262 +1,305 @@ -import { shallowMount, mount } from "@vue/test-utils"; +import { mount } from "@vue/test-utils"; import listButton from "./list-button"; -import { nextTick } from "vue"; import { GaActions } from "@/constants/analytics"; import inputButtonWrapperMixin from "@/mixins/input-button-wrapper-mixin"; -// TODO KO -describe.skip("list-button.vue", () => { - describe("loader", () => { - it("selectingInitiatesLoad is true and answer is changed => show the loader", async () => { - // Act - const { wrapper } = setupMocks({ - mockData: { - global: { - mocks: { - $route: { query: { fmgPage: "page-name" } }, - GaActions: GaActions, - pushEventToGA: jest.fn(), - }, - }, - propsData: { - selectingInitiatesLoad: true, - }, - }, - }); +describe("list-button.vue", () => { + describe("loader", () => { + it("selectingInitiatesLoad is true and answer is changed => show the loader", async () => { + // Act + const { wrapper } = setupMocks({ + mockData: { + global: { + mocks: { + $route: { query: { fmgPage: "page-name" } }, + GaActions: GaActions, + pushEventToGA: jest.fn(), + }, + }, + propsData: { + selectingInitiatesLoad: true, + }, + }, + }); - // Act - wrapper.vm.handleAnswerChange("something"); - await wrapper.vm.$nextTick(); + // Act + wrapper.vm.selectedValue = "something"; + await wrapper.vm.$nextTick(); - // Assert - const loader = wrapper.findComponent({ name: "loader" }); - expect(loader.exists()).toBe(true); + // Assert + console.log(wrapper.html()) + const loader = wrapper.findComponent({ name: "loader" }); + expect(loader.exists()).toBe(true); + }); + + it("Should return loader color", async () => { + // Arrange + const { wrapper } = setupMocks({ + mockData: { + global: { + mocks: { + $route: { query: { fmgPage: "page-name" } }, + GaActions: GaActions, + pushEventToGA: jest.fn(), + }, + }, + propsData: { + loaderColor: "blue", + selectingInitiatesLoad: true, + }, + }, + }); + + // Act + wrapper.vm.selectedValue = "something"; + await wrapper.vm.$nextTick(); + + // Assert + const loader = wrapper.findComponent({ name: "loader" }); + expect(loader.attributes("class")).toContain("blue"); + }); + + it("Should return loader position", async () => { + // Act + const { wrapper } = setupMocks({ + mockData: { + global: { + mocks: { + $route: { query: { fmgPage: "page-name" } }, + GaActions: GaActions, + pushEventToGA: jest.fn(), + }, + }, + propsData: { + loaderPosition: "right", + selectingInitiatesLoad: true, + }, + }, + }); + + // Act + wrapper.vm.selectedValue = "something"; + await wrapper.vm.$nextTick(); + + // Assert + const loader = wrapper.findComponent({ name: "loader" }); + expect(loader.attributes("class")).toContain("right"); + }); }); - it("Should return loader color", async () => { - // Act - const { wrapper } = setupMocks({ - mockData: { - global: { - mocks: { - $route: { query: { fmgPage: "page-name" } }, - GaActions: GaActions, - pushEventToGA: jest.fn(), - }, - }, - propsData: { - loaderColor: "blue", - selectingInitiatesLoad: true, - }, - }, - }); + describe("baseInputButton checks", () => { + it("Should return input type checkbox if isMultiSelect is true", async () => { + // Act + const { wrapper } = setupMocks({ + mockData: { + propsData: { + isMultiSelect: true, + }, + }, + }); - // Act - wrapper.vm.handleAnswerChange("something"); - await nextTick(); + // Assert + const input = wrapper.find("input"); - // Assert - const loader = wrapper.findComponent({ name: "loader" }); - expect(loader.attributes("class")).toContain("blue"); + expect(input.attributes().type).toEqual("checkbox"); + }); + + it("Should return input type radio if isMultiSelect is false or not specified", async () => { + // Act + const { wrapper } = setupMocks({ + mockData: { + propsData: { + isMultiSelect: false, + }, + }, + }); + + // Assert + const input = wrapper.find("input"); + expect(input.attributes().type).toEqual("radio"); + }); + + it("(Radio) Should emit button value on selectedValue change", async () => { + // Act + const { wrapper } = setupMocks({ + mockData: { + propsData: { + isRadioHorizontal: true, + buttonLabel: "Windshield", + value: "List Card Checkbox", + groupID: "radio-demo-1", + groupName: "radio1", + buttonImage: "windshield-damage.svg", + isRequired: true, + isWide: false, + modelValue: "List Card Checkbox", + buttonID: "list-card-id", + }, + }, + }); + + // Act + wrapper.vm.selectedValue = "test"; + + // Assert + expect(wrapper.emitted()["update:modelValue"][0][0]).toEqual("test"); + }); + + it("(Checkbox) Should emit button value on selectedValue change", async () => { + // Act + const { wrapper } = setupMocks({ + mockData: { + propsData: { + isRadioHorizontal: true, + buttonLabel: "Windshield", + value: "List Card Checkbox", + groupID: "radio-demo-1", + groupName: "radio 1", + buttonImage: "windshield-damage.svg", + isRequired: true, + isWide: false, + modelValue: "List Card Checkbox", + buttonID: "list-card-id", + isMultiSelect: true, + }, + }, + }); + + // Act + wrapper.vm.selectedValue = ["test"]; + + // Assert + expect(wrapper.emitted()["update:modelValue"][0][0]).toEqual(["test"]); + }); }); - it("Should return loader position", async () => { - // Act - const { wrapper } = setupMocks({ - mockData: { - global: { - mocks: { - $route: { query: { fmgPage: "page-name" } }, - GaActions: GaActions, - pushEventToGA: jest.fn(), - }, - }, - propsData: { - loaderPosition: "right", - selectingInitiatesLoad: true, - }, - }, - }); + describe("styling/UI", () => { + test("has buttonLabel => displays buttonLabel", () => { + // Arrange/Act + const { wrapper } = setupMocks({ + mockData: { + propsData: { + buttonLabel: "Surprise!", + modelValue: "", + groupName: "groupName", + value: "myValue" + }, + }, + }); - // Act - wrapper.vm.handleAnswerChange("test"); - await nextTick(); + // Assert + const content = wrapper.find(".list-button-content"); + expect(content.isVisible()).toBe(true); + expect(content.text()).toContain("Surprise!"); + }); - // Assert - const loader = wrapper.findComponent({ name: "loader" }); - expect(loader.attributes("class")).toContain("right"); + test("has buttonLabelSubCopy => displays buttonLabelSubCopy", () => { + // Arrange/Act + const { wrapper } = setupMocks({ + mockData: { + propsData: { + buttonLabel: "Surprise!", + buttonLabelSubCopy: "Super duper surprise :)", + modelValue: "", + groupName: "groupName", + value: "myValue" + }, + }, + }); + + // Assert + const content = wrapper.find(".list-button-content"); + expect(content.isVisible()).toBe(true); + expect(content.text()).toContain("Super duper surprise :)"); + }); + + test("has screenReaderOnlyText => displays screenReaderOnlyText", () => { + // Arrange/Act + const { wrapper } = setupMocks({ + mockData: { + propsData: { + buttonLabel: "Surprise!", + buttonLabelSubCopy: "Super duper surprise :)", + screenReaderOnlyText: "Tests are fun!", + modelValue: "", + groupName: "groupName", + value: "myValue" + }, + }, + }); + + // Assert + const content = wrapper.find(".list-button-content"); + const screenReaderOnlyText = wrapper.find(".sr-only"); + expect(content.isVisible()).toBe(true); + expect(screenReaderOnlyText.exists()).toBe(true); + expect(screenReaderOnlyText.text()).toContain("Tests are fun!"); + }); + + it("Should return screen reader text", async () => { + // Act + const { wrapper } = setupMocks({ + mockData: { + propsData: { + screenReaderOnlyText: "Screen Reader Only Text", + modelValue: "", + groupName: "groupName", + value: "myValue" + }, + }, + }); + + // Assert + const paragraph = wrapper.find("span.sr-only"); + + expect(paragraph.text()).toEqual("Screen Reader Only Text"); + }); + + it("Should return text alignment class", async () => { + // Act + const { wrapper } = setupMocks({ + mockData: { + propsData: { + textPosition: "text-center", + modelValue: "", + groupName: "groupName", + value: "myValue" + }, + }, + }); + + // Assert + const paragraph = wrapper.find("span.m-0"); + + expect(paragraph.attributes("class")).toContain("text-center"); + }); + + it("Should return aria-required state", async () => { + // Act + const { wrapper } = setupMocks({ + mockData: { + propsData: { + isRequired: true, + groupName: "groupName", + modelValue: "", + value: "myValue", + }, + }, + }); + + // Assert + const input = wrapper.find("input"); + + expect(input.attributes()["aria-required"]).toEqual("true"); + }); }); - }); - - describe("baseInputButton checks", () => { - it("Should return input type checkbox if isMultiSelect is true", async () => { - // Act - const { wrapper } = setupMocks({ - mockData: { - propsData: { - isMultiSelect: true, - }, - }, - }); - - // Assert - const input = wrapper.find("input"); - - expect(input.attributes().type).toEqual("checkbox"); - }); - - it("Should return input type radio if isMultiSelect is false or not specified", async () => { - // Act - const { wrapper } = setupMocks({ - mockData: { - propsData: { - isMultiSelect: false, - }, - }, - }); - - // Assert - const input = wrapper.find("input"); - expect(input.attributes().type).toEqual("radio"); - }); - - it("Should emit button value on click", async () => { - // Act - const { wrapper } = setupMocks({ - mockData: { - propsData: { - isRadioHorizontal: true, - buttonLabel: "Windshield", - value: "List Card Checkbox", - groupID: "radio-demo-1", - groupName: "radio 1", - buttonImage: "windshield-damage.svg", - isRequired: true, - isWide: false, - modelValue: ["List Card Checkbox"], - buttonID: "list-card-id", - }, - }, - }); - - // Act - wrapper.vm.handleAnswerChange("test"); - await wrapper.vm.$nextTick(); - - // Assert - expect(wrapper.emitted()["change"][0]).toEqual(["test"]); - }); - }); - - describe("styling/UI", () => { - test("has buttonLabel => displays buttonLabel", () => { - // Arrange/Act - const { wrapper } = setupMocks({ - mockData: { - propsData: { - buttonLabel: "Surprise!", - }, - }, - }); - - // Assert - const content = wrapper.find(".list-button-content"); - expect(content.isVisible()).toBe(true); - expect(content.text()).toContain("Surprise!"); - }); - - test("has buttonLabelSubCopy => displays buttonLabelSubCopy", () => { - // Arrange/Act - const { wrapper } = setupMocks({ - mockData: { - propsData: { - buttonLabel: "Surprise!", - buttonLabelSubCopy: "Super duper surprise :)", - }, - }, - }); - - // Assert - const content = wrapper.find(".list-button-content"); - expect(content.isVisible()).toBe(true); - expect(content.text()).toContain("Super duper surprise :)"); - }); - - test("has screenReaderOnlyText => displays screenReaderOnlyText", () => { - // Arrange/Act - const { wrapper } = setupMocks({ - mockData: { - propsData: { - buttonLabel: "Surprise!", - buttonLabelSubCopy: "Super duper surprise :)", - screenReaderOnlyText: "Tests are fun!", - }, - }, - }); - - // Assert - const content = wrapper.find(".list-button-content"); - const screenReaderOnlyText = wrapper.find(".sr-only"); - expect(content.isVisible()).toBe(true); - expect(screenReaderOnlyText.exists()).toBe(true); - expect(screenReaderOnlyText.text()).toContain("Tests are fun!"); - }); - - it("Should return screen reader text", async () => { - // Act - const { wrapper } = setupMocks({ - mockData: { - propsData: { - screenReaderOnlyText: "Screen Reader Only Text", - }, - }, - }); - - // Assert - const paragraph = wrapper.find("span.sr-only"); - - expect(paragraph.text()).toEqual("Screen Reader Only Text"); - }); - - it("Should return text alignment class", async () => { - // Act - const { wrapper } = setupMocks({ - mockData: { - propsData: { - textPosition: "text-center", - }, - }, - }); - - // Assert - const paragraph = wrapper.find("span.m-0"); - - expect(paragraph.attributes("class")).toContain("text-center"); - }); - - it("Should return aria-required state", async () => { - // Act - const { wrapper } = setupMocks({ - mockData: { - propsData: { - isRequired: true, - }, - }, - }); - - // Assert - const input = wrapper.find("input"); - - expect(input.attributes()["aria-required"]).toEqual("true"); - }); - }); }); function setupMocks({ mockData }) { - const wrapper = mount(listButton, { - ...mockData, - mixins: [inputButtonWrapperMixin], - }); + const wrapper = mount(listButton, { + ...mockData, + mixins: [inputButtonWrapperMixin], + }); - return { wrapper }; + return { wrapper }; } diff --git a/src/ux-components/list-button/list-button.vue b/src/ux-components/list-button/list-button.vue index 54ef98b35..6cc061eb7 100644 --- a/src/ux-components/list-button/list-button.vue +++ b/src/ux-components/list-button/list-button.vue @@ -52,6 +52,7 @@ export default { }, preHandleAnswerChange() { if (this.selectingInitiatesLoad) { + console.log("DISPLAY LOADER") this.displayLoader(); } }, From ad7785e15f2b06f82725a0a6026ae0f9a9ca1880 Mon Sep 17 00:00:00 2001 From: Katie Date: Thu, 20 Oct 2022 14:29:05 -0400 Subject: [PATCH 7/9] CSR-762 Add tests --- .../base-input-button.spec.js | 252 ++++++++++++++++-- src/ux-components/list-button/list-button.vue | 1 - 2 files changed, 229 insertions(+), 24 deletions(-) diff --git a/src/common-components/base-input-button/base-input-button.spec.js b/src/common-components/base-input-button/base-input-button.spec.js index 273f3d491..646e271a2 100644 --- a/src/common-components/base-input-button/base-input-button.spec.js +++ b/src/common-components/base-input-button/base-input-button.spec.js @@ -764,18 +764,207 @@ describe("baseInputButton.vue", () => { }); describe("handlePushClickEventToGACheck", () => { - test.todo("called from click or click-like event => call pushClickEventToGA"); + test("called from click or click-like event => call pushClickEventToGA", () => { + // Arrange + const { wrapper } = setupMocks({}); + wrapper.vm.pushEventToGA = jest.fn(); + + // Act + wrapper.vm.handlePushClickEventToGACheck("click"); + + // Assert + expect(wrapper.vm.pushEventToGA).toHaveBeenCalledTimes(1); + }); describe("called from keyboard navigation/button-question-focus-helper", () => { - test.todo("valueToEmit is null => pushClickEventToGA not called"); + test("valueToEmit is not null, is a checked radio without selectingInitiatesLoad, and the last value pushed to GA was not this input button's value => pushClickEventToGA is called", async () => { + // Arrange + const { wrapper } = setupMocks({ + mockData: { + propsData: { + isMultiSelect: false, + modelValue: "value2", + value: "value2", + selectingInitiatesLoad: false, + }, + }, + }); + wrapper.vm.pushEventToGA = jest.fn(); + await wrapper.setData({ + valueToEmit: "value2", + lastValuePushedToGa: "value1", + }); - test.todo("isMultiSelect => pushClickEventToGA not called"); + // Act + wrapper.vm.handlePushClickEventToGACheck(); - test.todo("!isMultiSelect and selectingInitiatesLoad => pushClickEventToGA not called"); + // Assert + expect(wrapper.vm.isChecked).toBe(true); + expect(wrapper.find("input").attributes().type).toBe("radio") + expect(wrapper.vm.pushEventToGA).toHaveBeenCalled(); + }); - test.todo("valueToEmit is null => pushClickEventToGA not called"); + test("valueToEmit is not null, is a checked radio with selectingInitiatesLoad, and the last value pushed to GA was not this input button's value => pushClickEventToGA is called", async () => { + // Arrange + const { wrapper } = setupMocks({ + mockData: { + propsData: { + isMultiSelect: false, + modelValue: "value2", + value: "value2", + selectingInitiatesLoad: true, + }, + }, + }); + wrapper.vm.pushEventToGA = jest.fn(); + await wrapper.setData({ + valueToEmit: "value2", + lastValuePushedToGa: "value1", + }); - test.todo("valueToEmit is null => pushClickEventToGA not called"); + // Act + wrapper.vm.handlePushClickEventToGACheck(); + + // Assert + expect(wrapper.vm.isChecked).toBe(true); + expect(wrapper.find("input").attributes().type).toBe("radio") + expect(wrapper.vm.pushEventToGA).not.toHaveBeenCalled(); + }); + + test("valueToEmit is not null, is a checkbox that's checked, and the last value pushed to GA was not this input button's value => pushClickEventToGA is not called", async () => { + // Arrange + const { wrapper } = setupMocks({ + mockData: { + propsData: { + isMultiSelect: true, + modelValue: ["value2"], + value: "value2", + selectingInitiatesLoad: false, + }, + }, + }); + wrapper.vm.pushEventToGA = jest.fn(); + await wrapper.setData({ + valueToEmit: "value2", + lastValuePushedToGa: "value1", + }); + + // Act + wrapper.vm.handlePushClickEventToGACheck(); + + // Assert + expect(wrapper.vm.isChecked).toBe(true); + expect(wrapper.find("input").attributes().type).toBe("checkbox") + expect(wrapper.vm.pushEventToGA).not.toHaveBeenCalled(); + }); + + test("valueToEmit is null => pushClickEventToGA not called", async () => { + // Arrange + const { wrapper } = setupMocks({ + mockData: { + propsData: { + isMultiSelect: false, + modelValue: "value2", + value: "value2", + selectingInitiatesLoad: false, + }, + }, + }); + wrapper.vm.pushEventToGA = jest.fn(); + await wrapper.setData({ + valueToEmit: null, + lastValuePushedToGa: "value1", + }); + + // Act + wrapper.vm.handlePushClickEventToGACheck(); + + // Assert + expect(wrapper.vm.isChecked).toBe(true); + expect(wrapper.find("input").attributes().type).toBe("radio") + expect(wrapper.vm.pushEventToGA).not.toHaveBeenCalled(); + }); + + test("valueToEmit is not null, is an unchecked checkbox, and the last value pushed to GA was not this input button's value => pushClickEventToGA is not called", async () => { + // Arrange + const { wrapper } = setupMocks({ + mockData: { + propsData: { + isMultiSelect: true, + modelValue: ["value1"], + value: "value2", + selectingInitiatesLoad: false, + }, + }, + }); + wrapper.vm.pushEventToGA = jest.fn(); + await wrapper.setData({ + valueToEmit: "value2", + lastValuePushedToGa: "value1", + }); + + // Act + wrapper.vm.handlePushClickEventToGACheck(); + + // Assert + expect(wrapper.vm.isChecked).toBe(false); + expect(wrapper.find("input").attributes().type).toBe("checkbox") + expect(wrapper.vm.pushEventToGA).not.toHaveBeenCalled(); + }); + + test("is an unchecked radio => pushClickEventToGA not called", async () => { + // Arrange + const { wrapper } = setupMocks({ + mockData: { + propsData: { + isMultiSelect: false, + modelValue: "value1", + value: "value2", + selectingInitiatesLoad: false, + }, + }, + }); + wrapper.vm.pushEventToGA = jest.fn(); + await wrapper.setData({ + valueToEmit: "value2", + lastValuePushedToGa: "value1", + }); + + // Act + wrapper.vm.handlePushClickEventToGACheck(); + + // Assert + expect(wrapper.vm.isChecked).toBe(false); + expect(wrapper.find("input").attributes().type).toBe("radio") + expect(wrapper.vm.pushEventToGA).not.toHaveBeenCalled(); + }); + + test("lastValuePushedToGa is the same as this input button's value => pushClickEventToGA not called", async () => { + // Arrange + const { wrapper } = setupMocks({ + mockData: { + propsData: { + isMultiSelect: false, + modelValue: "value2", + value: "value2", + selectingInitiatesLoad: false, + }, + }, + }); + wrapper.vm.pushEventToGA = jest.fn(); + await wrapper.setData({ + valueToEmit: "value2", + lastValuePushedToGa: "value2", + }); + + // Act + wrapper.vm.handlePushClickEventToGACheck(); + + // Assert + expect(wrapper.vm.isChecked).toBe(true); + expect(wrapper.find("input").attributes().type).toBe("radio") + expect(wrapper.vm.pushEventToGA).not.toHaveBeenCalled(); + }); }); }); @@ -791,8 +980,6 @@ describe("baseInputButton.vue", () => { }, }); - console.log(wrapper.vm.$route); - wrapper.setData({ GaActions: { CLICKED: "Clicked", @@ -813,7 +1000,40 @@ describe("baseInputButton.vue", () => { expect(wrapper.vm.setLastValuePushedToGa).toHaveBeenCalledWith("Bello"); }); - test.todo("set last value pushed to GA"); + test("pass in a value => setLastValuePushedToGa is called with value", () => { + // Arrange + const { wrapper } = setupMocks({ + mockData: { + propsData: { + setLastValuePushedToGa: jest.fn() + } + } + }); + + // Act + wrapper.vm.pushClickEventToGA("hi there"); + + // Assert + expect(wrapper.vm.setLastValuePushedToGa).toHaveBeenCalledWith("hi there") + }); + + test("don't pass in a value => setLastValuePushedToGa is called with input button's value", () => { + // Arrange + const { wrapper } = setupMocks({ + mockData: { + propsData: { + value: "hello there", + setLastValuePushedToGa: jest.fn() + } + } + }); + + // Act + wrapper.vm.pushClickEventToGA(); + + // Assert + expect(wrapper.vm.setLastValuePushedToGa).toHaveBeenCalledWith("hello there") + }); }); }); @@ -1011,20 +1231,6 @@ describe("baseInputButton.vue", () => { }); }); }); - - describe("keyboard navigation", () => { - describe("checkbox", () => { - test.todo("focus on a checkbox => update:modelValue is not emitted"); - - test.todo("blur from a checkbox => update:modelValue is not emitted"); - }); - - describe("radio", () => { - test.todo("focus on a radio button => update:modelValue is not emitted"); - - test.todo("blur from a radio button => update:modelValue is not emitted"); - }); - }); }); function setupMocks({ mockData = {}, shouldShallowMount = true }) { diff --git a/src/ux-components/list-button/list-button.vue b/src/ux-components/list-button/list-button.vue index 6cc061eb7..54ef98b35 100644 --- a/src/ux-components/list-button/list-button.vue +++ b/src/ux-components/list-button/list-button.vue @@ -52,7 +52,6 @@ export default { }, preHandleAnswerChange() { if (this.selectingInitiatesLoad) { - console.log("DISPLAY LOADER") this.displayLoader(); } }, From 06fe2f15be82e9218d36460c424beca7c5de0c19 Mon Sep 17 00:00:00 2001 From: Katie Date: Fri, 21 Oct 2022 08:04:42 -0400 Subject: [PATCH 8/9] CSR-762 tests --- src/mixins/input-button-wrapper-mixin.js | 1 + src/mixins/input-button-wrapper-mixin.spec.js | 107 ++++++++++++++++-- .../list-button-horizontal.spec.js | 61 ---------- .../list-button/list-button.spec.js | 1 - 4 files changed, 96 insertions(+), 74 deletions(-) diff --git a/src/mixins/input-button-wrapper-mixin.js b/src/mixins/input-button-wrapper-mixin.js index 1d0a0d103..1878de18b 100644 --- a/src/mixins/input-button-wrapper-mixin.js +++ b/src/mixins/input-button-wrapper-mixin.js @@ -10,6 +10,7 @@ export default { buttonLabel: [Number, String], buttonLabelSubCopy: String, buttonImage: String, + buttonImageId: String, altText: { type: String, default: "", diff --git a/src/mixins/input-button-wrapper-mixin.spec.js b/src/mixins/input-button-wrapper-mixin.spec.js index 8724a5dd9..c0028ddab 100644 --- a/src/mixins/input-button-wrapper-mixin.spec.js +++ b/src/mixins/input-button-wrapper-mixin.spec.js @@ -1,6 +1,10 @@ import { mount } from "@vue/test-utils"; import baseInputButton from "@/common-components/base-input-button/base-input-button"; import inputButtonWrapperMixin from "@/mixins/input-button-wrapper-mixin"; +import listButtonHorizontal from "@/ux-components/list-button-horizontal/list-button-horizontal"; +import listButton from "@/ux-components/list-button/list-button"; +import listCard from "@/ux-components/list-card/list-card"; +import radio from "@/ux-components/radio/radio"; describe("input-button-wrapper-mixin", () => { describe("mouse clicks", () => { @@ -184,21 +188,100 @@ describe("input-button-wrapper-mixin", () => { ); }); }); + + // shared checks between components that use input-button-wrapper-mixin + describe("shared checks", () => { + const inputButtonComponents = [listButtonHorizontal, listButton, listCard, radio]; + test.each(inputButtonComponents.map((x) => [x.name, x]))( + "%s - should return input type checkbox if isMultiSelect is true", + async (name, inputButtonComponent) => { + // Act + const { wrapper } = setupMocksForComponentsUsingInputButtonWrapperMixin({ + component: inputButtonComponent, + mockData: { + propsData: { + isMultiSelect: true, + }, + }, + }); + + // Assert + const input = wrapper.find("input"); + expect(input.attributes().type).toEqual("checkbox"); + } + ); + + test.each(inputButtonComponents.map((x) => [x.name, x]))( + "%s - return input type radio if isMultiSelect is false or not specified", + async (name, inputButtonComponent) => { + // Act + const { wrapper } = setupMocksForComponentsUsingInputButtonWrapperMixin({ + component: inputButtonComponent, + mockData: { + propsData: { + isMultiSelect: false, + }, + }, + }); + + // Assert + const input = wrapper.find("input"); + expect(input.attributes().type).toEqual("radio"); + } + ); + + const selectedValues = ["something", ["test"]]; + inputButtonComponents.forEach((inputButtonComponent) => { + test.each(selectedValues)( + `${inputButtonComponent.name} with selectedValue %s - should emit button value on click`, + async (selectedValue) => { + // Act + const { wrapper } = setupMocksForComponentsUsingInputButtonWrapperMixin({ + component: inputButtonComponent, + mockData: { + propsData: { + isRadioHorizontal: true, + buttonLabel: "Windshield", + value: "List Card Checkbox", + groupID: "radio-demo-1", + groupName: "radio 1", + buttonImage: "windshield-damage.svg", + isRequired: true, + isWide: false, + modelValue: ["List Card Checkbox"], + buttonID: "list-card-id", + }, + }, + }); + + // Act + wrapper.vm.selectedValue = selectedValue; + await wrapper.vm.$nextTick(); + + // Assert + expect(wrapper.emitted()["update:modelValue"][0][0]).toEqual(selectedValue); + } + ); + }); + }); }); -function setupBaseInputButtonWrapper({ mockData = {} }) { - const originalData = baseInputButton.data(); - baseInputButton.data = () => { - return { - ...originalData, - // $route: { - // query: { - // fmgPage: "myPage", - // }, - // }, - }; - }; +function setupMocksForComponentsUsingInputButtonWrapperMixin({ mockData, component }) { + const wrapper = mount(component, { + ...mockData, + propsData: { + ...mockData.propsData, + groupName: "my-group", + modelValue: mockData.propsData?.isMultiSelect ? ["5"] : "5", + value: "4", + }, + mixins: [inputButtonWrapperMixin], + }); + return { wrapper }; +} + +function setupBaseInputButtonWrapper({ mockData = {} }) { baseInputButton.methods.pushClickEventToGA = jest.fn(); const baseInputButtonWrapper = { diff --git a/src/ux-components/list-button-horizontal/list-button-horizontal.spec.js b/src/ux-components/list-button-horizontal/list-button-horizontal.spec.js index e101e5fc0..09a63b349 100644 --- a/src/ux-components/list-button-horizontal/list-button-horizontal.spec.js +++ b/src/ux-components/list-button-horizontal/list-button-horizontal.spec.js @@ -3,67 +3,6 @@ import listButtonHorizontal from "./list-button-horizontal"; import inputButtonWrapperMixin from "@/mixins/input-button-wrapper-mixin"; describe("list-button-horizontal.vue", () => { - // TODO KO Have this moved out to somewhere shared - describe("Shared baseInputButton checks", () => { - it("Should return input type checkbox if isMultiSelect is true", async () => { - // Act - const { wrapper } = setupMocks({ - mockData: { - propsData: { - isMultiSelect: true, - }, - }, - }); - - // Assert - const input = wrapper.find("input"); - expect(input.attributes().type).toEqual("checkbox"); - }); - - it("Should return input type radio if isMultiSelect is false or not specified", async () => { - // Act - const { wrapper } = setupMocks({ - mockData: { - propsData: { - isMultiSelect: false, - }, - }, - }); - - // Assert - const input = wrapper.find("input"); - expect(input.attributes().type).toEqual("radio"); - }); - - const selectedValues = ["something", ["test"]] - it.each(selectedValues)("Should emit button value on click", async (selectedValue) => { - // Act - const { wrapper } = setupMocks({ - mockData: { - propsData: { - isRadioHorizontal: true, - buttonLabel: "Windshield", - value: "List Card Checkbox", - groupID: "radio-demo-1", - groupName: "radio 1", - buttonImage: "windshield-damage.svg", - isRequired: true, - isWide: false, - modelValue: ["List Card Checkbox"], - buttonID: "list-card-id", - }, - }, - }); - - // Act - wrapper.vm.selectedValue = selectedValue; - await wrapper.vm.$nextTick(); - - // Assert - expect(wrapper.emitted()["update:modelValue"][0][0]).toEqual(selectedValue); - }); - }); - describe("styling/UI", () => { it("Should return screen reader text", async () => { // Act diff --git a/src/ux-components/list-button/list-button.spec.js b/src/ux-components/list-button/list-button.spec.js index d932b1ea3..0b4909420 100644 --- a/src/ux-components/list-button/list-button.spec.js +++ b/src/ux-components/list-button/list-button.spec.js @@ -27,7 +27,6 @@ describe("list-button.vue", () => { await wrapper.vm.$nextTick(); // Assert - console.log(wrapper.html()) const loader = wrapper.findComponent({ name: "loader" }); expect(loader.exists()).toBe(true); }); From f8c11140f1750fcd9f7de3c592ed13478dfd082d Mon Sep 17 00:00:00 2001 From: Katie Date: Fri, 21 Oct 2022 10:56:53 -0400 Subject: [PATCH 9/9] CSR-762 Reset code coverage threshold --- jest.config.js | 2 +- .../windshield-chip-count-question.spec.js | 8 + src/layouts/vehicle-make/vehicle-make.spec.js | 282 +++++++++++------- 3 files changed, 187 insertions(+), 105 deletions(-) diff --git a/jest.config.js b/jest.config.js index 4af0d88cc..ded486df9 100644 --- a/jest.config.js +++ b/jest.config.js @@ -28,7 +28,7 @@ module.exports = { testMatch: ["**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)"], coverageThreshold: { global: { - statements: 80, + statements: 85, // Got the go ahead from Mark to temporarily lower this. Taking out initialize component made the year,make,model and style coverage drop a bit. Once unit tests for license plate lookup, vin lookup and address lookup are in the coverage should go back up to 90 }, }, diff --git a/src/layouts/vehicle-damage/windshield-options/windshield-chip-count-question/windshield-chip-count-question.spec.js b/src/layouts/vehicle-damage/windshield-options/windshield-chip-count-question/windshield-chip-count-question.spec.js index 795606526..902e0808a 100644 --- a/src/layouts/vehicle-damage/windshield-options/windshield-chip-count-question/windshield-chip-count-question.spec.js +++ b/src/layouts/vehicle-damage/windshield-options/windshield-chip-count-question/windshield-chip-count-question.spec.js @@ -22,6 +22,14 @@ describe("windshield-chip-count-question.vue", () => { //Assert expect(wrapper.emitted()["update:modelValue"][0]).toEqual([2]); }); + + test("selectedValue matches modelValue", () => { + // Arrange/Act + const { wrapper } = setupMocks({ modelValueProp: 2 }); + + // Assert + expect(wrapper.vm.selectedValue).toBe(2); + }); }); function setupMocks({ diff --git a/src/layouts/vehicle-make/vehicle-make.spec.js b/src/layouts/vehicle-make/vehicle-make.spec.js index c5ec3cba9..c533516ce 100644 --- a/src/layouts/vehicle-make/vehicle-make.spec.js +++ b/src/layouts/vehicle-make/vehicle-make.spec.js @@ -5,150 +5,224 @@ import { settleAllPromises } from "@/helpers/layout-helper.js"; import { nextTick } from "vue"; import { fetchCmsContentForPage } from "@/helpers/cms-content-helper"; import baseMixin from "@/mixins/base-mixin.js"; +import store from "@/store"; // Components import vehicleMake from "@/layouts/vehicle-make/vehicle-make.vue"; import makeQuestion from "@/layouts/vehicle-make/make-question/make-question"; jest.mock("@/store", () => ({ - commit: jest.fn(), - dispatch: jest.fn(), - getters: { - vehicle: { - year: 2019, - }, - }, + commit: jest.fn(), + dispatch: jest.fn(), + // getters: jest.fn().mockImplementation(() => ({ + // vehicle: { + // year: 2019, + // }, + // })), })); // Mock fetchCmsContentForPage jest.mock("@/helpers/cms-content-helper", () => ({ - fetchCmsContentForPage: jest.fn(), + fetchCmsContentForPage: jest.fn(), })); // Mock our module for promises. jest.mock("@/helpers/layout-helper.js", () => ({ - settleAllPromises: jest.fn(), + settleAllPromises: jest.fn(), })); - describe("vehicle-make.vue", () => { - test("Make question component is initized with api data", async (done) => { - //Arrange - const makeQuestionInitialData = ["honda", "ford", "dodge"]; - const { wrapper, apiPromise } = setupMocks({ - makeQuestionInitialData: makeQuestionInitialData, - }); + test("Make question component is initized with api data", async (done) => { + //Arrange + const makeQuestionInitialData = ["honda", "ford", "dodge"]; + const { wrapper, apiPromise } = setupMocks({ + makeQuestionInitialData: makeQuestionInitialData, + }); - //Act - vehicleMake.beforeRouteEnter.call( - wrapper.vm, - { query: { fmgPage: "vehicle-make" } }, - undefined, - (c) => c(wrapper.vm) - ); + //Act + vehicleMake.beforeRouteEnter.call( + wrapper.vm, + { query: { fmgPage: "vehicle-make" } }, + undefined, + (c) => c(wrapper.vm) + ); - //Assert - apiPromise.finally(() => { - expect(makeQuestion.methods.initializeComponent).toHaveBeenCalledWith( - makeQuestionInitialData - ); - done(); + //Assert + apiPromise.finally(() => { + expect(makeQuestion.methods.initializeComponent).toHaveBeenCalledWith( + makeQuestionInitialData + ); + done(); + }); }); - }); }); describe("vehicle-make.vue", () => { - test("BackButtonAction triggers a router.navigateWithoutSaving change", async (done) => { - //Arrange - const { wrapper, apiPromise } = setupMocks({ - pageHeaderWidgetHeaderText: "Select a make to get started", - mountOptionsMockData: { - router: { - navigate: jest.fn(), - navigateWithoutSaving: jest.fn(), - }, - }, - }); + test("BackButtonAction triggers a router.navigateWithoutSaving change", async (done) => { + //Arrange + const { wrapper, apiPromise } = setupMocks({ + pageHeaderWidgetHeaderText: "Select a make to get started", + mountOptionsMockData: { + router: { + navigate: jest.fn(), + navigateWithoutSaving: jest.fn(), + }, + }, + }); - //Act - vehicleMake.beforeRouteEnter.call( - wrapper.vm, - { query: { fmgPage: "vehicle-make" } }, - undefined, - (c) => c(wrapper.vm) - ); - wrapper.vm.backButtonAction(); - await nextTick(); + //Act + vehicleMake.beforeRouteEnter.call( + wrapper.vm, + { query: { fmgPage: "vehicle-make" } }, + undefined, + (c) => c(wrapper.vm) + ); + wrapper.vm.backButtonAction(); + await nextTick(); - //Assert - apiPromise.finally(() => { - expect(wrapper.vm.$router.navigateWithoutSaving).toHaveBeenCalled(); - done(); + //Assert + apiPromise.finally(() => { + expect(wrapper.vm.$router.navigateWithoutSaving).toHaveBeenCalled(); + done(); + }); }); - }); }); describe("vehicle-make.vue", () => { - test("Year set, arePagePrerequisitesValid should be true ", async () => { - //Arrange - const { wrapper } = setupMocks({}); + describe("arePagePrerequisitesValue", () => { + test("Year set, arePagePrerequisitesValid should be true", async () => { + //Arrange + const { wrapper } = setupMocks({ + vehicleData: { + year: 2019 + } + }); - //Act - vehicleMake.beforeRouteEnter.call( - wrapper.vm, - { query: { fmgPage: "vehicle-make" } }, - undefined, - (c) => c(wrapper.vm) - ); + //Act + vehicleMake.beforeRouteEnter.call( + wrapper.vm, + { query: { fmgPage: "vehicle-make" } }, + undefined, + (c) => c(wrapper.vm) + ); - let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid(); + let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid(); - //Assert - expect(arePagePrerequisitesValid).toBe(true); - }); + //Assert + expect(arePagePrerequisitesValid).toBe(true); + }); + + test("Year not set, arePagePrerequisitesValid should be false", async () => { + //Arrange + store.getters.vehicle.year = jest.fn().mockReturnValueOnce(undefined); + const { wrapper } = setupMocks({}); + + //Act + let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid(); + + //Assert + expect(arePagePrerequisitesValid).toBe(false); + }); + }); + + test("selectedMake changes => save make in store", async () => { + //Arrange + const { wrapper } = setupMocks({ + mountOptionsMockData: { + router: { + navigate: jest.fn(), + navigateWithSaving: jest.fn(), + }, + } + }); + + // Act + await wrapper.setData({ + selectedMake: "Make", + }); + await wrapper.vm.$nextTick(); + + // Assert + expect(wrapper.vm.dispatchStoreAction).toHaveBeenCalledTimes(1); + expect(wrapper.vm.dispatchStoreAction).toHaveBeenCalledWith( + "saveVehicleMake", + "Make", + false + ); + }); + + test("selectedMake changes => navigate with saving", async () => { + //Arrange + const { wrapper } = setupMocks({ + mountOptionsMockData: { + router: { + navigate: jest.fn(), + navigateWithSaving: jest.fn(), + }, + route: { + fmgPage: "test", + }, + }, + }); + + // Act + await wrapper.setData({ + selectedMake: "Make", + }); + + // Assert + expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalledTimes(1); + expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalledWith( + "SELECTED_MAKE", + expect.anything() + ); + }); }); - function setupMocks({ - vehicleMakeQuestionCmsContent = {}, - makeQuestionInitialData = {}, - pageHeaderWidgetHeaderText = {}, - mountOptionsMockData = {}, + vehicleMakeQuestionCmsContent = {}, + makeQuestionInitialData = {}, + pageHeaderWidgetHeaderText = {}, + mountOptionsMockData = {}, + vehicleData = {} }) { - //Mock api responses - const apiResponses = { - cmsContent: { - FunnelSubHeaderWidget: pageHeaderWidgetHeaderText, - VehicleMakeQuestion: vehicleMakeQuestionCmsContent, - VehicleBannerWidget: { - GenericVehicleImage: - "https://digitalconsumercms-dev.safelite.com/images/default-source/default-album/blurred-image.jpg?sfvrsn=a6ce3034_3", - }, - FunnelHeaderWidget: { - LogoImage: - "https://digitalconsumercms-dev.safelite.com/images/default-source/default-album/safelite-logo.svg?sfvrsn=45e7ed06_3", - }, - }, - makeQuestionInitialData: makeQuestionInitialData, - }; + //Mock api responses + const apiResponses = { + cmsContent: { + FunnelSubHeaderWidget: pageHeaderWidgetHeaderText, + VehicleMakeQuestion: vehicleMakeQuestionCmsContent, + VehicleBannerWidget: { + GenericVehicleImage: + "https://digitalconsumercms-dev.safelite.com/images/default-source/default-album/blurred-image.jpg?sfvrsn=a6ce3034_3", + }, + FunnelHeaderWidget: { + LogoImage: + "https://digitalconsumercms-dev.safelite.com/images/default-source/default-album/safelite-logo.svg?sfvrsn=45e7ed06_3", + }, + }, + makeQuestionInitialData: makeQuestionInitialData, + }; - const apiPromise = Promise.resolve(apiResponses); + const apiPromise = Promise.resolve(apiResponses); - fetchCmsContentForPage.mockImplementation(() => Promise.resolve()); - settleAllPromises.mockImplementation(() => apiPromise); + store.getters = { + vehicle: vehicleData + } - //Mock make question methods - makeQuestion.methods = { - loadInitialData: jest.fn(), - initializeComponent: jest.fn(), - }; + fetchCmsContentForPage.mockImplementation(() => Promise.resolve()); + settleAllPromises.mockImplementation(() => apiPromise); - const mountOptions = getMountOptions(mountOptionsMockData); - const wrapper = shallowMount(vehicleMake, mountOptions); - const makeQuestionWrapper = wrapper.findComponent({ name: "makeQuestion" }); - makeQuestionWrapper.vm.initializeComponent = - makeQuestion.methods.initializeComponent; + //Mock make question methods + makeQuestion.methods = { + loadInitialData: jest.fn(), + initializeComponent: jest.fn(), + }; + + const mountOptions = getMountOptions(mountOptionsMockData); + const wrapper = shallowMount(vehicleMake, mountOptions); + const makeQuestionWrapper = wrapper.findComponent({ name: "makeQuestion" }); + makeQuestionWrapper.vm.initializeComponent = makeQuestion.methods.initializeComponent; wrapper.vm.setCmsContent = baseMixin.methods.setCmsContent; - return { wrapper, apiPromise }; + return { wrapper, apiPromise }; }