From 2c6ae4fb4e8b0cbf9fc6f54d6d402af7975def46 Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Tue, 21 Jul 2026 15:35:07 -0400 Subject: [PATCH] Unit test updates + compatibility changes. --- .../modal-button-main.spec.js | 42 ------ .../modal-button-main/modal-button-main.vue | 3 +- src/fmg-components/nav-bar/nav-bar.spec.js | 8 +- .../shop-list-button/shop-list-button.vue | 2 +- .../button-main/button-main.spec.js | 42 ------ .../intercept-overlay.spec.js | 28 +++- .../list-button/list-button.spec.js | 53 -------- src/ux-components/list-button/list-button.vue | 3 +- src/ux-components/loader/loader.spec.js | 121 +++++++++++------- 9 files changed, 108 insertions(+), 194 deletions(-) diff --git a/src/digital-components/modal/ux-components/modal-button-main/modal-button-main.spec.js b/src/digital-components/modal/ux-components/modal-button-main/modal-button-main.spec.js index f212d8ec3..24cb8e546 100644 --- a/src/digital-components/modal/ux-components/modal-button-main/modal-button-main.spec.js +++ b/src/digital-components/modal/ux-components/modal-button-main/modal-button-main.spec.js @@ -36,48 +36,6 @@ describe("modal-button-main.vue", () => { 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( diff --git a/src/digital-components/modal/ux-components/modal-button-main/modal-button-main.vue b/src/digital-components/modal/ux-components/modal-button-main/modal-button-main.vue index c12dfe498..a2991dcea 100644 --- a/src/digital-components/modal/ux-components/modal-button-main/modal-button-main.vue +++ b/src/digital-components/modal/ux-components/modal-button-main/modal-button-main.vue @@ -13,7 +13,8 @@ + :loaderColor="loaderColor" + :loaderPosition="loaderPosition" /> diff --git a/src/fmg-components/nav-bar/nav-bar.spec.js b/src/fmg-components/nav-bar/nav-bar.spec.js index 68b9f6c8c..c7ed0e934 100644 --- a/src/fmg-components/nav-bar/nav-bar.spec.js +++ b/src/fmg-components/nav-bar/nav-bar.spec.js @@ -33,21 +33,15 @@ describe("nav-bar.vue", () => { expect(wrapper.componentVM.customButtontext).toBe("newText"); }); - test("should run removeLoader fn on buttonMain and return false for onkeydown fn", async () => { - // Arrange + test("should run removeLoader on buttonMain", async () => { const wrapper = mount(navbar, { mixins: [mockMixin], }); - // Act wrapper.vm.$refs.buttonMain.removeLoader = jest.fn(); wrapper.vm.removeLoader(); - const spy = jest.spyOn(document, "onkeydown"); - document.onkeydown(); - // Assert expect(wrapper.vm.$refs.buttonMain.removeLoader).toHaveBeenCalled(); - expect(spy).toReturnWith(true); }); }); diff --git a/src/layouts/service-location/shop-question/shop-list-button/shop-list-button.vue b/src/layouts/service-location/shop-question/shop-list-button/shop-list-button.vue index dda3f9281..f16c3536b 100644 --- a/src/layouts/service-location/shop-question/shop-list-button/shop-list-button.vue +++ b/src/layouts/service-location/shop-question/shop-list-button/shop-list-button.vue @@ -27,7 +27,7 @@ diff --git a/src/ux-components/button-main/button-main.spec.js b/src/ux-components/button-main/button-main.spec.js index 76e9afe28..9324726a0 100644 --- a/src/ux-components/button-main/button-main.spec.js +++ b/src/ux-components/button-main/button-main.spec.js @@ -36,48 +36,6 @@ describe("buttonMain.vue", () => { expect(button.attributes()["aria-disabled"]).toEqual("true"); }); - it("Should return loader color", async () => { - // Arrange - const wrapper = shallowMount( - buttonMain, - 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( - buttonMain, - 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( diff --git a/src/ux-components/intercept-overlay/intercept-overlay.spec.js b/src/ux-components/intercept-overlay/intercept-overlay.spec.js index 0a282b93d..e43fc884d 100644 --- a/src/ux-components/intercept-overlay/intercept-overlay.spec.js +++ b/src/ux-components/intercept-overlay/intercept-overlay.spec.js @@ -1,4 +1,4 @@ -import { shallowMount } from "@vue/test-utils"; +import { mount, shallowMount } from "@vue/test-utils"; import interceptOverlay from "./intercept-overlay"; describe("intercept-overlay.vue", () => { @@ -43,4 +43,30 @@ describe("intercept-overlay.vue", () => { wrapper.unmount(); }); }); + + describe("click interception", () => { + test("captureClick prevents default and stops propagation", () => { + const wrapper = shallowMount(interceptOverlay); + const event = { preventDefault: jest.fn(), stopPropagation: jest.fn() }; + wrapper.vm.captureClick(event); + expect(event.preventDefault).toHaveBeenCalled(); + expect(event.stopPropagation).toHaveBeenCalled(); + wrapper.unmount(); + }); + + test("clicking the overlay does not propagate to document listeners", async () => { + const documentClickFn = jest.fn(); + document.addEventListener("click", documentClickFn); + + const wrapper = mount(interceptOverlay, { attachTo: document.body }); + + const overlay = wrapper.find(".intercept-overlay"); + await overlay.trigger("click"); + + expect(documentClickFn).not.toHaveBeenCalled(); + + document.removeEventListener("click", documentClickFn); + wrapper.unmount(); + }); + }); }); diff --git a/src/ux-components/list-button/list-button.spec.js b/src/ux-components/list-button/list-button.spec.js index 721ef8a43..a3de44080 100644 --- a/src/ux-components/list-button/list-button.spec.js +++ b/src/ux-components/list-button/list-button.spec.js @@ -31,59 +31,6 @@ describe("list-button.vue", () => { 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"); - }); }); describe("baseInputButton checks", () => { diff --git a/src/ux-components/list-button/list-button.vue b/src/ux-components/list-button/list-button.vue index df71f9800..5ca26f738 100644 --- a/src/ux-components/list-button/list-button.vue +++ b/src/ux-components/list-button/list-button.vue @@ -18,7 +18,8 @@ + :loaderColor="loaderColor" + :loaderPosition="loaderPosition" /> diff --git a/src/ux-components/loader/loader.spec.js b/src/ux-components/loader/loader.spec.js index d56c4e0ed..4b79efb36 100644 --- a/src/ux-components/loader/loader.spec.js +++ b/src/ux-components/loader/loader.spec.js @@ -3,18 +3,16 @@ import loader from "./loader"; describe("loader.vue", () => { test("if it rendered the HTML element with class", () => { - // Arrange/Act const wrapper = shallowMount(loader, { props: {}, }); - // Assert expect(wrapper.find("div").exists()).toBeTruthy(); expect(wrapper.find(".loader").exists()).toBeTruthy(); + wrapper.unmount(); }); - test("if it correctly passed props", () => { - // Arrange/Act + test("applies loaderColor and loaderPosition as CSS classes on the loader element", () => { const wrapper = shallowMount(loader, { props: { loaderColor: "blue", @@ -22,64 +20,95 @@ describe("loader.vue", () => { }, }); - // Assert - expect(wrapper.props()).toMatchObject({ - loaderColor: "blue", - loaderPosition: "left", - }); + const loaderElement = wrapper.find(".loader"); + expect(loaderElement.classes()).toContain("blue"); + expect(loaderElement.classes()).toContain("left"); + wrapper.unmount(); }); describe("Blocking interaction on page", () => { - test("Does capture clicks if enabled (default)", async () => { - // Arrange - const div = document.createElement("div"); - div.id = "parent"; - document.body.appendChild(div); + let parent; - const parentClickFn = jest.fn(); - - div.addEventListener("click", parentClickFn); - - const wrapper = shallowMount(loader, { - props: {}, - attachTo: "#parent", - }); - - // Act - await wrapper.trigger("click"); - - // Assert - expect(parentClickFn).not.toBeCalled(); - - // Cleanup - document.body.removeChild(div); + beforeEach(() => { + parent = document.createElement("div"); + parent.id = "loader-test-parent"; + document.body.appendChild(parent); }); - test("Does not capture clicks if disabled", async () => { - // Arrange - const div = document.createElement("div"); - div.id = "parent"; - document.body.appendChild(div); + afterEach(() => { + document.body.querySelectorAll(".intercept-overlay").forEach((el) => el.remove()); + if (parent?.parentNode) { + parent.parentNode.removeChild(parent); + } + }); - const parentClickFn = jest.fn(); + test("teleports intercept overlay to document.body when blocking is enabled", () => { + const wrapper = mount(loader, { + props: {}, + attachTo: "#loader-test-parent", + }); - div.addEventListener("click", parentClickFn); + const overlayInBody = document.body.querySelector(".intercept-overlay"); + const overlayInParent = parent.querySelector(".intercept-overlay"); - const wrapper = shallowMount(loader, { + expect(overlayInBody).toBeTruthy(); + expect(overlayInParent).toBeNull(); + expect(wrapper.find(".intercept-overlay").exists()).toBe(false); + + wrapper.unmount(); + }); + + test("does not render intercept overlay when allowPageInteraction is true", () => { + const wrapper = mount(loader, { props: { allowPageInteraction: true, }, - attachTo: "#parent", + attachTo: "#loader-test-parent", }); - // Act - await wrapper.trigger("click"); + expect(document.body.querySelector(".intercept-overlay")).toBeNull(); + expect(wrapper.find(".loader").exists()).toBe(true); - // Assert - expect(parentClickFn).toBeCalled(); + wrapper.unmount(); + }); - // Cleanup - document.body.removeChild(div); + test("clicking the teleported overlay does not propagate to document listeners", async () => { + const documentClickFn = jest.fn(); + document.addEventListener("click", documentClickFn); + + const wrapper = mount(loader, { + props: {}, + attachTo: "#loader-test-parent", + }); + + const overlay = document.body.querySelector(".intercept-overlay"); + expect(overlay).toBeTruthy(); + + overlay.dispatchEvent(new MouseEvent("click", { bubbles: true, cancelable: true })); + + expect(documentClickFn).not.toHaveBeenCalled(); + + document.removeEventListener("click", documentClickFn); + wrapper.unmount(); + }); + + test("teleports overlay to body even when loader is mounted inside a button", async () => { + const button = document.createElement("button"); + button.type = "button"; + parent.appendChild(button); + + const wrapper = mount(loader, { + props: {}, + attachTo: button, + }); + + const overlayInBody = document.body.querySelector(".intercept-overlay"); + const overlayInButton = button.querySelector(".intercept-overlay"); + + expect(overlayInBody).toBeTruthy(); + expect(overlayInButton).toBeNull(); + + wrapper.unmount(); }); }); });