From b1ac5130e82a6bdd066e71fb9716738a10731667 Mon Sep 17 00:00:00 2001 From: Jason Wheeler Date: Fri, 31 Mar 2023 10:51:30 -0400 Subject: [PATCH 01/11] added modal vue and started test page --- src/digital-components/modal/modal.spec.js | 269 +++++++++++++++--- src/digital-components/modal/modal.vue | 125 +++++--- src/digital-components/modal/modal_old.vue | 144 ++++++++++ src/helpers/unit-test-helper.js | 2 + .../content-group-modal.spec.js | 67 +++++ .../content-group-modal.vue | 86 ++++++ src/layouts/entry-page/entry-page.vue | 4 +- .../part-questions/part-questions.spec.js | 2 +- src/layouts/z-test-page-jg/z-test-page-jg.vue | 87 ++++++ .../list-button/list-button.spec.js | 6 +- .../modal-button-main.spec.js | 188 ++++++++++++ .../modal-button-main/modal-button-main.vue | 153 ++++++++++ 12 files changed, 1043 insertions(+), 90 deletions(-) create mode 100644 src/digital-components/modal/modal_old.vue create mode 100644 src/iss-components/content-group-modal/content-group-modal.spec.js create mode 100644 src/iss-components/content-group-modal/content-group-modal.vue create mode 100644 src/layouts/z-test-page-jg/z-test-page-jg.vue create mode 100644 src/ux-components/modal-button-main/modal-button-main.spec.js create mode 100644 src/ux-components/modal-button-main/modal-button-main.vue 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..ba7e60eb 100644 --- a/src/digital-components/modal/modal.vue +++ b/src/digital-components/modal/modal.vue @@ -2,39 +2,38 @@ + + From 4a08cbf38d06c5aca65a1dccbd3ab983caaf58f0 Mon Sep 17 00:00:00 2001 From: Jason Wheeler Date: Thu, 6 Apr 2023 14:58:12 -0400 Subject: [PATCH 05/11] half way there --- src/digital-components/modal/modal.vue | 4 ++-- src/layouts/z-test-page-jg/z-test-page-jg.vue | 17 ++++++++++++++++- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/digital-components/modal/modal.vue b/src/digital-components/modal/modal.vue index e13f4fcd..87330d06 100644 --- a/src/digital-components/modal/modal.vue +++ b/src/digital-components/modal/modal.vue @@ -91,11 +91,11 @@ export default { }, openModal() { const modal = Modal.getOrCreateInstance(document.getElementById(this.modalId)); - modal.show(); + modal?.show(); }, closeModal() { const modal = Modal.getInstance(document.getElementById(this.modalId)); - modal.hide(); + modal?.hide(); }, }, computed: { diff --git a/src/layouts/z-test-page-jg/z-test-page-jg.vue b/src/layouts/z-test-page-jg/z-test-page-jg.vue index c994900d..eae6b414 100644 --- a/src/layouts/z-test-page-jg/z-test-page-jg.vue +++ b/src/layouts/z-test-page-jg/z-test-page-jg.vue @@ -14,7 +14,7 @@ here

- Wow!! + Wow!! { + const element = document.getElementById("test"); + element.addEventListener("click", () => app.openModal("ModalName") ) + } + ), + */ + mounted() { + console.log(document.getElementById("test")) + console.log(this.openModal); + const element = document.getElementById("test"); + const modalname = "ModalName"; + const openModal = this.openModal; + element.addEventListener("click", () => openModal(modalname) ) + }, computed: { bodyText() { return this.getCmsContent("ModalLink", "BodyText"); From c83604c64d779f25e6a8f4f65bf2a1a244097367 Mon Sep 17 00:00:00 2001 From: Jason Wheeler Date: Mon, 10 Apr 2023 16:46:50 -0400 Subject: [PATCH 06/11] figured out that I needed to run the processing of the modal-links on the next tick. --- src/helpers/cms-content-helper.js | 4 +- .../coverage-statement/coverage-statement.vue | 49 ++++++++++++------- .../recal-modal/recal-modal.vue | 8 +++ src/layouts/z-test-page-jg/z-test-page-jg.vue | 29 +++++------ src/styles/common-styles.scss | 6 +++ 5 files changed, 59 insertions(+), 37 deletions(-) diff --git a/src/helpers/cms-content-helper.js b/src/helpers/cms-content-helper.js index 36bf7c70..0b4c29ee 100644 --- a/src/helpers/cms-content-helper.js +++ b/src/helpers/cms-content-helper.js @@ -173,8 +173,8 @@ function mapStringToModal(str) { let params = linkToReplace.substring((dynamicStrings.MODAL_LINK).length + 2, linkToReplace.length -1) let splitParams = params.split(","); - let bodyText = '' + splitParams[1] +'' - + //let bodyText = '' + splitParams[1] +'' + let bodyText = '' + splitParams[1] + '' return str.replace(linkToReplace, bodyText); } diff --git a/src/layouts/coverage-statement/coverage-statement.vue b/src/layouts/coverage-statement/coverage-statement.vue index 8fcbfb79..7a24a3ac 100644 --- a/src/layouts/coverage-statement/coverage-statement.vue +++ b/src/layouts/coverage-statement/coverage-statement.vue @@ -43,9 +43,8 @@ /> - + - - - \ No newline at end of file diff --git a/src/helpers/cms-content-helper.js b/src/helpers/cms-content-helper.js index 0b4c29ee..656b2b5f 100644 --- a/src/helpers/cms-content-helper.js +++ b/src/helpers/cms-content-helper.js @@ -173,9 +173,14 @@ function mapStringToModal(str) { let params = linkToReplace.substring((dynamicStrings.MODAL_LINK).length + 2, linkToReplace.length -1) let splitParams = params.split(","); - //let bodyText = '' + splitParams[1] +'' + let bodyText = '' + splitParams[1] + '' - return str.replace(linkToReplace, bodyText); + let returnVal = str.replace(linkToReplace, bodyText) + + if (returnVal.includes(dynamicStrings.MODAL_LINK)) { + returnVal = mapStringToModal(returnVal); + } + return returnVal; } // Function to convert a string, into a matching global state item. @@ -214,7 +219,20 @@ function mapStringToState(str) { } return stringBuilder.trimStart(); - } +} + +export function setupModalLinks(context) { + context.$nextTick(() => { + const elements = document.getElementsByClassName("modal-text") + for(let element of elements){ + const target = element.getAttribute("modalTarget"); + if(target) + { + element.addEventListener("click", () => context.$refs[target].openModal() ); + } + }; + }); +} export function doesCopyContainRouterLink(copy) { return copy.includes(this.dynamicStrings.ROUTER_LINK); diff --git a/src/layouts/coverage-statement/coverage-statement.vue b/src/layouts/coverage-statement/coverage-statement.vue index 7a24a3ac..2bc1d946 100644 --- a/src/layouts/coverage-statement/coverage-statement.vue +++ b/src/layouts/coverage-statement/coverage-statement.vue @@ -58,7 +58,7 @@ import textBlock from "@/digital-components/text-block/text-block"; import recalModal from '@/layouts/coverage-statement/recal-modal/recal-modal.vue'; // Import Supporting Files -import { fetchCmsContentForPage } from '@/helpers/cms-content-helper'; +import { fetchCmsContentForPage, setupModalLinks } from '@/helpers/cms-content-helper'; import { settleAllPromises } from '@/helpers/layout-helper'; import { getDamageString } from '@/helpers/damage-helper.js'; import { useMainStore } from "@/store"; @@ -111,21 +111,7 @@ export default { }, }, mounted() { - this.$nextTick(() => { - const elements = document.getElementsByClassName("modal-text") - console.log(elements); - - for(let element of elements){ - console.log(element); - const target = element.getAttribute("modalTarget"); - console.log("HERE!!!!" + target); - if(target) - { - console.log("HERE!!!!"); - element.addEventListener("click", () => this.$refs[target].openModal() ); - } - }; - }); + setupModalLinks(this); }, async beforeRouteEnter(to, from, next) { // Call APIs diff --git a/src/layouts/coverage-statement/recal-modal/recal-modal.vue b/src/layouts/coverage-statement/recal-modal/recal-modal.vue index a7285ab3..0a360174 100644 --- a/src/layouts/coverage-statement/recal-modal/recal-modal.vue +++ b/src/layouts/coverage-statement/recal-modal/recal-modal.vue @@ -3,7 +3,8 @@ :ref="ModalName" :modalId="ModalName" :footerButtonText="ModalCloseButtonText" - > + @footer-button-event="closeModal" + >
From d56b963b45e4d44b2755163d7834d38347cc0b3d Mon Sep 17 00:00:00 2001 From: Jason Wheeler Date: Tue, 11 Apr 2023 13:59:27 -0400 Subject: [PATCH 08/11] updated provider preference modal --- .../provider-preference/provider-preference.vue | 14 +++++++++++--- src/styles/common-styles.scss | 7 +++++++ 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/layouts/provider-preference/provider-preference.vue b/src/layouts/provider-preference/provider-preference.vue index 11bf45f7..b1cddf69 100644 --- a/src/layouts/provider-preference/provider-preference.vue +++ b/src/layouts/provider-preference/provider-preference.vue @@ -14,7 +14,7 @@ v-html="ProviderPreferenceBodyText" class="mt-0 body-text" >
- + + \ No newline at end of file diff --git a/src/layouts/coverage-statement/recal-modal/recal-modal.spec.js b/src/layouts/coverage-statement/recal-modal/recal-modal.spec.js index 3ab73b9a..0f555171 100644 --- a/src/layouts/coverage-statement/recal-modal/recal-modal.spec.js +++ b/src/layouts/coverage-statement/recal-modal/recal-modal.spec.js @@ -1,10 +1,10 @@ -import { shallowMount } from "@vue/test-utils"; +import { shallowMount, mount } from "@vue/test-utils"; import recalModal from "@/layouts/coverage-statement/recal-modal/recal-modal.vue"; describe("modal.vue", () => { it("Should display header text when HeaderText is defined in the CMS", async () => { // Act - const wrapper = shallowMount(recalModal, { + const wrapper = mount(recalModal, { mixins: [mockMixin], props: { cmsWidgetName: "test", @@ -16,7 +16,7 @@ describe("modal.vue", () => { it("Should display subheader text when SubheaderText is defined in the CMS", async () => { // Act - const wrapper = shallowMount(recalModal, { + const wrapper = mount(recalModal, { mixins: [mockMixin], props: { cmsWidgetName: "test", @@ -28,7 +28,7 @@ describe("modal.vue", () => { it("Should insert image url when Image is defined in the CMS", async () => { // Act - const wrapper = shallowMount(recalModal, { + const wrapper = mount(recalModal, { mixins: [mockMixin], props: { cmsWidgetName: "test", @@ -40,7 +40,7 @@ describe("modal.vue", () => { it("Should display body text when BodyText is defined in the CMS", async () => { // Act - const wrapper = shallowMount(recalModal, { + const wrapper = mount(recalModal, { mixins: [mockMixin], props: { cmsWidgetName: "test", diff --git a/src/layouts/provider-preference/provider-preference.vue b/src/layouts/provider-preference/provider-preference.vue index b1cddf69..f4064ffa 100644 --- a/src/layouts/provider-preference/provider-preference.vue +++ b/src/layouts/provider-preference/provider-preference.vue @@ -58,7 +58,6 @@ import { Form,defineRule } from "vee-validate"; import siteFooter from "@/iss-components/site-footer/site-footer.vue"; import siteHeader from "@/iss-components/site-header/site-header.vue"; import siteSubHeader from "@/iss-components/site-sub-header/site-sub-header.vue"; -import shoppreferenceModal from '@/layouts/provider-preference/shoppreference-modal/shoppreference-modal.vue'; // DEFINE VALIDATION RULES defineRule("questions-required", required(errorMessages.OPTION_REQUIRED)); @@ -71,7 +70,6 @@ export default { siteHeader, siteSubHeader, Form, - shoppreferenceModal, buttonQuestion, contentGroupModal }, diff --git a/src/layouts/provider-preference/shoppreference-modal/shoppreference-modal.spec.js b/src/layouts/provider-preference/shoppreference-modal/shoppreference-modal.spec.js deleted file mode 100644 index 21be705f..00000000 --- a/src/layouts/provider-preference/shoppreference-modal/shoppreference-modal.spec.js +++ /dev/null @@ -1,41 +0,0 @@ -import { shallowMount } from "@vue/test-utils"; -import shoppreferenceModal from '@/layouts/provider-preference/shoppreference-modal/shoppreference-modal.vue'; - -describe("modal.vue", () => { - it("Should display header text when HeaderText is defined in the CMS", async () => { - // Act - const wrapper = shallowMount(shoppreferenceModal, { - mixins: [mockMixin], - props: { - cmsWidgetName: "test", - }, - attachTo: document.body, - }); - expect(wrapper.html()).toEqual(expect.stringContaining(mockCmsContent["HeaderText"])); - }); - - it("Should display body text when BodyText is defined in the CMS", async () => { - // Act - const wrapper = shallowMount(shoppreferenceModal, { - mixins: [mockMixin], - props: { - cmsWidgetName: "test", - }, - attachTo: document.body, - }); - expect(wrapper.html()).toEqual(expect.stringContaining(mockCmsContent["BodyText"])); - }); -}); - const mockMixin = { - methods: { - getCmsContent: jest.fn((widgetName, cmsFieldName) => { - return mockCmsContent[cmsFieldName]; - }), - }, - }; - - const mockCmsContent = { - HeaderText: "Sample header text here.", - BodyText: "Sample body text here.", - FooterText: "Sample footer text here.", - }; \ No newline at end of file diff --git a/src/layouts/provider-preference/shoppreference-modal/shoppreference-modal.vue b/src/layouts/provider-preference/shoppreference-modal/shoppreference-modal.vue deleted file mode 100644 index 8cc521b9..00000000 --- a/src/layouts/provider-preference/shoppreference-modal/shoppreference-modal.vue +++ /dev/null @@ -1,137 +0,0 @@ - - - - - From a28e1dc5782bdd90583d8cbedbaa3a6917926126 Mon Sep 17 00:00:00 2001 From: Jason Wheeler Date: Tue, 11 Apr 2023 14:21:23 -0400 Subject: [PATCH 10/11] removed test page --- src/layouts/z-test-page-jg/z-test-page-jg.vue | 110 ------------------ 1 file changed, 110 deletions(-) delete mode 100644 src/layouts/z-test-page-jg/z-test-page-jg.vue diff --git a/src/layouts/z-test-page-jg/z-test-page-jg.vue b/src/layouts/z-test-page-jg/z-test-page-jg.vue deleted file mode 100644 index d0cc8723..00000000 --- a/src/layouts/z-test-page-jg/z-test-page-jg.vue +++ /dev/null @@ -1,110 +0,0 @@ - - - \ No newline at end of file From 273c4b43d1e4febb551e53837a3b1df6ee8863ba Mon Sep 17 00:00:00 2001 From: Jethe Date: Wed, 12 Apr 2023 13:45:17 +0530 Subject: [PATCH 11/11] Updated the "Terms of use" to "Terms of service" SSR-397 --- src/iss-components/site-header/menu-modal/menu-modal.spec.js | 4 ++-- src/iss-components/site-header/menu-modal/menu-modal.vue | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/iss-components/site-header/menu-modal/menu-modal.spec.js b/src/iss-components/site-header/menu-modal/menu-modal.spec.js index 22f598f5..1b1f9aa5 100644 --- a/src/iss-components/site-header/menu-modal/menu-modal.spec.js +++ b/src/iss-components/site-header/menu-modal/menu-modal.spec.js @@ -24,12 +24,12 @@ describe("menu-modal.vue", () => { expect(modalFooter.text()).toContain("Safelite Group"); }); - it("Should return Terms of use text link text", async () => { + it("Should return Terms of service text link text", async () => { // Act const wrapper = shallowMount(menuModal); // Expect - expect(wrapper.html()).toContain("Terms of use"); + expect(wrapper.html()).toContain("Terms of service"); }); it('Should return "Your privacy choices" text link text', async () => { diff --git a/src/iss-components/site-header/menu-modal/menu-modal.vue b/src/iss-components/site-header/menu-modal/menu-modal.vue index 6fc1047b..214076d0 100644 --- a/src/iss-components/site-header/menu-modal/menu-modal.vue +++ b/src/iss-components/site-header/menu-modal/menu-modal.vue @@ -16,7 +16,7 @@