diff --git a/src/digital-components/modal/modal.spec.js b/src/digital-components/modal/modal.spec.js index 2664accf..e4d8692d 100644 --- a/src/digital-components/modal/modal.spec.js +++ b/src/digital-components/modal/modal.spec.js @@ -1,68 +1,255 @@ +jest.mock("vee-validate", () => ({ + useForm: jest.fn(), +})); + +const mockValidate = (returnValue) => jest.fn(async () => Promise.resolve({ valid: returnValue })); +const mockMeta = (returnValue) => jest.fn(async () => Promise.resolve(returnValue)); + import { shallowMount } from "@vue/test-utils"; -import Modal from "./modal"; +import modal from "./modal"; +import crypto from "crypto"; +import { useForm } from "vee-validate"; +import { Modal } from "bootstrap"; + +const footerButtonText = "Sample footer text here."; +const headerText = "Sample header text here."; + +global.crypto = crypto; describe("modal.vue", () => { - it("Should display header text when HeaderText is defined in the CMS", async () => { - // Act - const wrapper = shallowMount(Modal, { - mixins: [mockMixin], + it("Should display modal header text when headerText is defined", async () => { + // Arrange / Act + const fakeMeta = { + touched: true, + dirty: true, + valid: true, + validated: true, + }; + + useForm.mockReturnValue({ + meta: mockMeta(fakeMeta), + validate: mockValidate(true), + }); + + const wrapper = shallowMount(modal, { props: { - cmsWidgetName: "test", + headerText: headerText, + footerButtonText: footerButtonText, }, attachTo: document.body, }); - expect(wrapper.html()).toEqual(expect.stringContaining(mockCmsContent["HeaderText"])); + + // Assert + expect(wrapper.html()).toEqual(expect.stringContaining(headerText)); }); - it("Should display subheader text when SubheaderText is defined in the CMS", async () => { - // Act - const wrapper = shallowMount(Modal, { - mixins: [mockMixin], + it("Should display footer button text when footerButtonText is defined", async () => { + // Arrange / Act + const fakeMeta = { + touched: true, + dirty: true, + valid: true, + validated: true, + }; + + useForm.mockReturnValue({ + meta: mockMeta(fakeMeta), + validate: mockValidate(true), + }); + const wrapper = shallowMount(modal, { props: { - cmsWidgetName: "test", + footerButtonText: footerButtonText, }, attachTo: document.body, }); - expect(wrapper.html()).toEqual(expect.stringContaining(mockCmsContent["SubheaderText"])); + + // Assert + expect(wrapper.html()).toEqual(expect.stringContaining(footerButtonText)); }); - it("Should insert image url when Image is defined in the CMS", async () => { - // Act - const wrapper = shallowMount(Modal, { - mixins: [mockMixin], + it("Should emit 'footer-button-event' if the form is valid", async () => { + // Arrange + const fakeMeta = { + touched: true, + dirty: true, + valid: true, + validated: true, + }; + + useForm.mockReturnValue({ + meta: mockMeta(fakeMeta), + validate: mockValidate(true), + }); + + const resetButtonStyle = jest.fn(); + const wrapper = shallowMount(modal, { props: { - cmsWidgetName: "test", + footerButtonText: footerButtonText, + headerText: headerText, }, attachTo: document.body, }); - expect(wrapper.html()).toEqual(expect.stringContaining(mockCmsContent["Image"])); + wrapper.vm.resetButtonStyle = resetButtonStyle; + + // Act + const buttonMain = wrapper.findComponent({ ref: "modalButtonMain" }); + await buttonMain.trigger("click-event"); + + // Assert + expect(wrapper.emitted("footer-button-event")).toBeTruthy(); }); - it("Should display body text when BodyText is defined in the CMS", async () => { - // Act - const wrapper = shallowMount(Modal, { - mixins: [mockMixin], + it("Should not emit 'footer-button-event' if the form is invalid", async () => { + // Arrange + const fakeMeta = { + touched: true, + dirty: true, + valid: false, + validated: true, + }; + + useForm.mockReturnValue({ + meta: mockMeta(fakeMeta), + validate: mockValidate(false), + }); + + const resetButtonStyle = jest.fn(); + const wrapper = shallowMount(modal, { props: { - cmsWidgetName: "test", + footerButtonText: footerButtonText, + headerText: headerText, }, attachTo: document.body, }); - expect(wrapper.html()).toEqual(expect.stringContaining(mockCmsContent["BodyText"])); + wrapper.vm.resetButtonStyle = resetButtonStyle; + + // Act + const buttonMain = wrapper.findComponent({ ref: "modalButtonMain" }); + await buttonMain.trigger("click-event"); + + // Assert + expect(wrapper.emitted("footer-button-event")).toBeFalsy(); + }); + + it("Should have a disabled footer button when the form has not been touched", async () => { + // Arrange / Act + const fakeMeta = { + touched: true, + dirty: true, + valid: true, + validated: true, + }; + + useForm.mockReturnValue({ + meta: mockMeta(fakeMeta), + validate: mockValidate(true), + }); + + const resetButtonStyle = jest.fn(); + const wrapper = shallowMount(modal, { + props: { + footerButtonText: footerButtonText, + headerText: headerText, + }, + attachTo: document.body, + }); + wrapper.vm.resetButtonStyle = resetButtonStyle; + + // Assert + expect(wrapper.vm.isFooterButtonDisabled).toBe(true); + }); + + it("Should have a disabled footer button when the form is invalid", async () => { + // Arrange / Act + const fakeMeta = { + touched: true, + dirty: true, + valid: true, + validated: true, + }; + + useForm.mockReturnValue({ + meta: mockMeta(fakeMeta), + validate: mockValidate(true), + }); + + const resetButtonStyle = jest.fn(); + const wrapper = shallowMount(modal, { + props: { + footerButtonText: footerButtonText, + headerText: headerText, + }, + attachTo: document.body, + }); + wrapper.vm.resetButtonStyle = resetButtonStyle; + + // Assert + expect(wrapper.vm.isFooterButtonDisabled).toBe(true); + }); + + it("Should call bootstrap Modal method 'show' when calling 'openModal'", async () => { + // Arrange + const fakeMeta = { + touched: true, + dirty: true, + valid: true, + validated: true, + }; + + useForm.mockReturnValue({ + meta: mockMeta(fakeMeta), + validate: mockValidate(true), + }); + + const showMock = jest.spyOn(Modal.prototype, "show"); + + const resetButtonStyle = jest.fn(); + const wrapper = shallowMount(modal, { + props: { + footerButtonText: footerButtonText, + headerText: headerText, + }, + attachTo: document.body, + }); + wrapper.vm.resetButtonStyle = resetButtonStyle; + + // Act + wrapper.vm.openModal(); + + // Assert + expect(showMock).toHaveBeenCalled(); + }); + + it("Should call bootstrap Modal method 'hide' when calling 'closeModal'", async () => { + // Arrange + const fakeMeta = { + touched: true, + dirty: true, + valid: true, + validated: true, + }; + + useForm.mockReturnValue({ + meta: mockMeta(fakeMeta), + validate: mockValidate(true), + }); + const hideMock = jest.spyOn(Modal.prototype, "hide"); + + const resetButtonStyle = jest.fn(); + const wrapper = shallowMount(modal, { + props: { + footerButtonText: footerButtonText, + headerText: headerText, + }, + attachTo: document.body, + }); + wrapper.vm.resetButtonStyle = resetButtonStyle; + + // Act + wrapper.vm.openModal(); + wrapper.vm.closeModal(); + + // Assert + expect(hideMock).toHaveBeenCalled(); }); }); - -const mockMixin = { - methods: { - getCmsContent: jest.fn((widgetName, cmsFieldName) => { - return mockCmsContent[cmsFieldName]; - }), - }, -}; - -const mockCmsContent = { - HeaderText: "Sample header text here.", - SubheaderText: "Sample subheader text here.", - Image: "https://www.sampleImage.sample", - BodyText: "Sample body text here.", - FooterText: "Sample footer text here.", -}; diff --git a/src/digital-components/modal/modal.vue b/src/digital-components/modal/modal.vue index 8d961830..fb06197d 100644 --- a/src/digital-components/modal/modal.vue +++ b/src/digital-components/modal/modal.vue @@ -2,39 +2,38 @@ + diff --git a/src/styles/common-styles.scss b/src/styles/common-styles.scss index 92f3478d..73e01e30 100644 --- a/src/styles/common-styles.scss +++ b/src/styles/common-styles.scss @@ -63,4 +63,11 @@ body { overflow: hidden; } } -} + + .modal-text { + display: inline; + color: $blue; + cursor: pointer; + text-decoration: underline; + } +} \ No newline at end of file diff --git a/src/ux-components/list-button/list-button.spec.js b/src/ux-components/list-button/list-button.spec.js index 3b7d267d..3ed2ba6a 100644 --- a/src/ux-components/list-button/list-button.spec.js +++ b/src/ux-components/list-button/list-button.spec.js @@ -11,7 +11,7 @@ describe("list-button.vue", () => { mockData: { global: { mocks: { - $route: { query: { fmgPage: "page-name" } }, + $route: { query: { issPage: "page-name" } }, GaActions: GaActions, pushEventToGA: jest.fn(), }, @@ -37,7 +37,7 @@ describe("list-button.vue", () => { mockData: { global: { mocks: { - $route: { query: { fmgPage: "page-name" } }, + $route: { query: { issPage: "page-name" } }, GaActions: GaActions, pushEventToGA: jest.fn(), }, @@ -64,7 +64,7 @@ describe("list-button.vue", () => { mockData: { global: { mocks: { - $route: { query: { fmgPage: "page-name" } }, + $route: { query: { issPage: "page-name" } }, GaActions: GaActions, pushEventToGA: jest.fn(), }, diff --git a/src/ux-components/modal-button-main/modal-button-main.spec.js b/src/ux-components/modal-button-main/modal-button-main.spec.js new file mode 100644 index 00000000..621f3d4c --- /dev/null +++ b/src/ux-components/modal-button-main/modal-button-main.spec.js @@ -0,0 +1,188 @@ +import { shallowMount } from "@vue/test-utils"; +import modalButtonMain from "./modal-button-main"; +import { getMountOptions } from "@/helpers/unit-test-helper.js"; +import { nextTick } from "vue"; + +describe("modal-button-main.vue", () => { + it("Should return btn-primary class", () => { + // Arrange/Act + const wrapper = shallowMount( + modalButtonMain, + setupMocks({ + propsData: { + isPrimary: true, + }, + }) + ); + const button = wrapper.find("button"); + + // Assert + expect(button.attributes("class")).toContain("btn-primary"); + }); + + it("Should return aria-disabled state", () => { + // Arrange/Act + const wrapper = shallowMount( + modalButtonMain, + setupMocks({ + propsData: { + isDisabled: true, + }, + }) + ); + const button = wrapper.find("button"); + + // Assert + expect(button.attributes()["aria-disabled"]).toEqual("true"); + }); + + it("Should return loader color", async () => { + // Arrange + const wrapper = shallowMount( + modalButtonMain, + setupMocks({ + propsData: { + loaderColor: "blue", + loaderEnabled: true, + }, + }) + ); + + // Act + wrapper.vm.clicked(); + + await nextTick(); + + // Assert + const loader = wrapper.find("loader-stub"); + expect(loader.attributes("class")).toContain("blue"); + }); + + it("Should return loader position", async () => { + // Arrange + const wrapper = shallowMount( + modalButtonMain, + setupMocks({ + propsData: { + loaderPosition: "right", + loaderEnabled: true, + }, + }) + ); + + // Act + wrapper.vm.clicked(); + await nextTick(); + + // Assert + const loader = wrapper.find("loader-stub"); + expect(loader.attributes("class")).toContain("right"); + }); + + it("Should set 'isLoaderDisplayed' to false when calling 'removeLoader'", async () => { + // Arrange + const wrapper = shallowMount( + modalButtonMain, + setupMocks({ + propsData: { + loaderPosition: "right", + loaderEnabled: true, + }, + }) + ); + + wrapper.setData({ + isLoaderDisplayed: true, + }); + + // Act + wrapper.vm.removeLoader(); + await nextTick(); + + // Assert + const loader = wrapper.find("loader-stub"); + expect(wrapper.vm.isLoaderDisplayed).toBe(false); + }); + + it("Should set 'isLoaderDisplayed' to false when calling 'resetButtonStyle'", async () => { + // Arrange + const wrapper = shallowMount( + modalButtonMain, + setupMocks({ + propsData: { + loaderPosition: "right", + loaderEnabled: true, + }, + }) + ); + + wrapper.setData({ + isLoaderDisplayed: true, + }); + + // Act + wrapper.vm.resetButtonStyle(); + await nextTick(); + + // Assert + expect(wrapper.vm.isLoaderDisplayed).toBe(false); + }); + + it("Should emit 'click-event' event when clicking if the button is enabled", async () => { + // Arrange + const wrapper = shallowMount( + modalButtonMain, + setupMocks({ + propsData: { + loaderPosition: "right", + loaderEnabled: true, + isDisabled: false, + }, + }) + ); + + const buttonElement = wrapper.find("button"); + + // Act + buttonElement.trigger("click"); + + await nextTick(); + + // Assert + expect(wrapper.emitted("click-event")).toBeTruthy(); + }); + + it("Should not emit 'click-event' event when clicking if the button is disabled", async () => { + // Arrange + const wrapper = shallowMount( + modalButtonMain, + setupMocks({ + propsData: { + loaderPosition: "right", + loaderEnabled: true, + isDisabled: true, + }, + }) + ); + + const buttonElement = wrapper.find("button"); + + // Act + buttonElement.trigger("click"); + + await nextTick(); + + // Assert + expect(wrapper.emitted("click-event")).toBeFalsy(); + }); +}); + +function setupMocks(mountOptionsMockData = {}) { + const defaultMountOptions = { route: { query: { issPage: "page-name" } } }; + const baseMountOptions = getMountOptions( + Object.assign(defaultMountOptions, mountOptionsMockData) + ); + const allMountOptions = Object.assign(defaultMountOptions, baseMountOptions); + + return allMountOptions; +} diff --git a/src/ux-components/modal-button-main/modal-button-main.vue b/src/ux-components/modal-button-main/modal-button-main.vue new file mode 100644 index 00000000..3cf8f7a2 --- /dev/null +++ b/src/ux-components/modal-button-main/modal-button-main.vue @@ -0,0 +1,153 @@ + + + + +