diff --git a/src/fmg-components/cart/cart.vue b/src/fmg-components/cart/cart.vue index f4626caa5..8add7bb85 100644 --- a/src/fmg-components/cart/cart.vue +++ b/src/fmg-components/cart/cart.vue @@ -87,20 +87,15 @@ @click-event="removeItem(cartItem.cartItemType, cartItem.category)" /> {{ recycleFeeCartItem.name }} - - Info Icon - + {{ msrFeeCartItem.name }} - - Info Icon - + - - - @@ -177,9 +165,9 @@ // Components import textLink from "@/ux-components/text-link/text-link"; import textBlock from "@/digital-components/text-block/text-block"; -import contentGroupModal from "@/fmg-components/content-group-modal/content-group-modal"; import promoModalQuestion from "@/fmg-components/promo-modal-question/promo-modal-question"; import removeMsrFeeModal from "./remove-msr-fee-modal/remove-msr-fee-modal.vue"; +import toolTip from "@/ux-components/tool-tip/tool-tip.vue"; // Mixins import baseMixin from "@/mixins/base-mixin.js"; @@ -1015,7 +1003,10 @@ export default { msrFeeLineItem.laborAmount + msrFeeLineItem.sellingPrice + msrFeeLineItem.kitPrice ); }, - msrModalTextBlock() { + recyclingToolTipBodyText() { + return this.getCmsContent("RecycleTextBlock", "Text"); + }, + msrToolTipBodyText() { let cmsContentText = this.getCmsContent("MSRModal", "BodyText"); if (cmsContentText) { cmsContentText = cmsContentText.replaceAll( @@ -1287,9 +1278,9 @@ export default { components: { textBlock, textLink, - contentGroupModal, promoModalQuestion, removeMsrFeeModal, + toolTip, }, }; diff --git a/src/ux-components/tool-tip/tool-tip.spec.js b/src/ux-components/tool-tip/tool-tip.spec.js new file mode 100644 index 000000000..1e4cca40e --- /dev/null +++ b/src/ux-components/tool-tip/tool-tip.spec.js @@ -0,0 +1,121 @@ +import { shallowMount, mount } from "@vue/test-utils"; +import toolTip from "@/ux-components/tool-tip/tool-tip.vue"; + +const mockMixin = { + methods: { + getCmsContent: jest.fn(() => "Mock CMS Content"), + }, +}; + +function setupMocks(mountOptionsMockData = {}) { + const defaultMountOptions = { + propsData: { + cmsWidgetName: "testWidget", + }, + mixins: [mockMixin], + }; + return { ...defaultMountOptions, ...mountOptionsMockData }; +} + +describe("toolTip.vue", () => { + afterEach(() => { + jest.clearAllMocks(); + }); + + it("should not show tooltip initially", () => { + // Arrange + const wrapper = shallowMount(toolTip, setupMocks()); + + // Assert + expect(wrapper.vm.isVisible).toBe(false); + expect(wrapper.find(".tooltip").exists()).toBe(false); + }); + + it("should show tooltip when icon is clicked", async () => { + // Arrange + const wrapper = shallowMount(toolTip, setupMocks()); + const icon = wrapper.find(".tooltip-icon"); + + // Act + await icon.trigger("click"); + + // Assert + expect(wrapper.vm.isVisible).toBe(true); + expect(wrapper.find(".tooltip").exists()).toBe(true); + }); + + it("should hide tooltip when clicked outside", async () => { + // Arrange + const wrapper = shallowMount(toolTip, setupMocks()); + const icon = wrapper.find(".tooltip-icon"); + + // Show tooltip first + await icon.trigger("click"); + expect(wrapper.vm.isVisible).toBe(true); + + // Act - simulate click outside + const clickEvent = new Event("click"); + Object.defineProperty(clickEvent, "target", { value: document.body }); + document.dispatchEvent(clickEvent); + + // Wait for next tick to allow event handling + await wrapper.vm.$nextTick(); + + // Assert + expect(wrapper.vm.isVisible).toBe(false); + expect(wrapper.find(".tooltip").exists()).toBe(false); + }); + + it("should toggle tooltip visibility when icon is clicked multiple times", async () => { + // Arrange + const wrapper = shallowMount(toolTip, setupMocks()); + const icon = wrapper.find(".tooltip-icon"); + + // Act & Assert - First click shows + await icon.trigger("click"); + expect(wrapper.vm.isVisible).toBe(true); + + // Second click hides + await icon.trigger("click"); + expect(wrapper.vm.isVisible).toBe(false); + + // Third click shows again + await icon.trigger("click"); + expect(wrapper.vm.isVisible).toBe(true); + }); + + it("should not hide tooltip when clicking inside the tooltip container", async () => { + // Arrange + const wrapper = shallowMount(toolTip, setupMocks()); + const icon = wrapper.find(".tooltip-icon"); + + // Show tooltip first + await icon.trigger("click"); + expect(wrapper.vm.isVisible).toBe(true); + + // Act - simulate click inside container + const container = wrapper.find(".tooltip-container").element; + const clickEvent = new Event("click"); + Object.defineProperty(clickEvent, "target", { value: container }); + document.dispatchEvent(clickEvent); + + // Wait for next tick + await wrapper.vm.$nextTick(); + + // Assert - tooltip should still be visible + expect(wrapper.vm.isVisible).toBe(true); + }); + + it("should calculate lineItemContainerLength based on parent element width", () => { + // Arrange + const wrapper = mount(toolTip, setupMocks()); + const parentDiv = document.createElement("div"); + Object.defineProperty(parentDiv, "offsetWidth", { value: 300, writable: true }); + + const container = wrapper.vm.$refs.container; + Object.defineProperty(container, "parentElement", { value: parentDiv, writable: true }); + + // Act & Assert + expect(wrapper.vm.lineItemContainerLength).toBe(-300); + }); +}); diff --git a/src/ux-components/tool-tip/tool-tip.vue b/src/ux-components/tool-tip/tool-tip.vue new file mode 100644 index 000000000..648c5adbd --- /dev/null +++ b/src/ux-components/tool-tip/tool-tip.vue @@ -0,0 +1,140 @@ + + + + +