import { useState } from "react"; import { act, fireEvent, waitFor } from "@testing-library/react"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { initSwatches } from "./mountSwatches"; const productMarkup = `
`; const suppressExpectedReactError = (event: ErrorEvent) => { event.preventDefault(); }; const getProductElements = () => { const container = document.querySelector( ".b3-wvs-swatches-container", ); const original = document.querySelector( ".b3-wvs-original-select", ); const select = document.querySelector("select"); if (!container || !original || !select) { throw new Error("Product fixture did not render."); } return { container, original, select }; }; describe("initSwatches error recovery", () => { beforeEach(() => { document.body.innerHTML = productMarkup; vi.spyOn(console, "error").mockImplementation(() => undefined); window.addEventListener("error", suppressExpectedReactError); }); afterEach(() => { window.removeEventListener("error", suppressExpectedReactError); vi.restoreAllMocks(); document.body.innerHTML = ""; }); it("reveals the native select when the swatch renderer fails on its initial render", async () => { const BrokenSwatches = () => { throw new Error("initial swatch failure"); }; await act(async () => { initSwatches({ SwatchGroupComponent: BrokenSwatches }); }); const { container, original, select } = getProductElements(); await waitFor(() => { expect(original.style.display).toBe(""); expect(container.classList.contains("b3-wvs-fallback")).toBe(true); expect(container.classList.contains("b3-wvs-initialized")).toBe(false); }); const change = vi.fn(); select.addEventListener("change", change); fireEvent.change(select, { target: { value: "blue" } }); expect(select.value).toBe("blue"); expect(change).toHaveBeenCalledOnce(); }); it("reveals the native select when the swatch renderer fails after mounting", async () => { const FailsOnUpdate = () => { const [failed, setFailed] = useState(false); if (failed) { throw new Error("later swatch failure"); } return ( ); }; await act(async () => { initSwatches({ SwatchGroupComponent: FailsOnUpdate }); }); const trigger = await waitFor(() => document.querySelector("button"), ); if (!trigger) { throw new Error("Swatch fixture did not mount."); } fireEvent.click(trigger); const { container, original } = getProductElements(); await waitFor(() => { expect(original.style.display).toBe(""); expect(container.classList.contains("b3-wvs-fallback")).toBe(true); expect(container.classList.contains("b3-wvs-initialized")).toBe(false); }); }); it("keeps the native select hidden after a successful swatch mount", async () => { const WorkingSwatches = () =>
Rendered swatches
; await act(async () => { initSwatches({ SwatchGroupComponent: WorkingSwatches }); }); const { container, original } = getProductElements(); expect(original.style.display).toBe("none"); expect(container.classList.contains("b3-wvs-initialized")).toBe(true); expect(container.classList.contains("b3-wvs-fallback")).toBe(false); expect(document.body.textContent).toContain("Rendered swatches"); }); }); describe("initSwatches with forms cloned after initialization", () => { const swatchMarkup = `
`; beforeEach(() => { document.body.innerHTML = `
${swatchMarkup}
`; }); afterEach(() => { document.body.innerHTML = ""; }); it("mounts a fresh, selectable renderer into a clone of an initialized form", async () => { await act(async () => { initSwatches(); }); const original = document.querySelector( "#product .b3-wvs-swatches-container", )!; await waitFor(() => expect(original.querySelectorAll('[role="radio"]')).toHaveLength(2), ); // A quick-view/drawer script copies the live, initialized markup. const clone = original.cloneNode(true) as HTMLElement; document.getElementById("drawer")!.append(clone); expect( clone.querySelector(".b3-wvs-swatches-mount")!.dataset .b3WvsMounted, ).toBe("1"); await act(async () => { initSwatches(); }); const cloneSelect = clone.querySelector("select")!; await waitFor(() => expect(clone.querySelectorAll('[role="radio"]')).toHaveLength(2), ); const cloneBlue = clone.querySelector( '[data-b3-wvs-radio-value="blue"]', )!; await act(async () => { fireEvent.click(cloneBlue); }); expect(cloneSelect.value).toBe("blue"); expect(cloneBlue.getAttribute("aria-checked")).toBe("true"); expect( clone.querySelector(".b3-wvs-original-select")!.style .display, ).toBe("none"); // The original form keeps its own independent selection state. expect(original.querySelector("select")!.value).toBe(""); }); it("does not remount a mount this module already owns", async () => { await act(async () => { initSwatches(); }); const mount = document.querySelector( ".b3-wvs-swatches-mount", )!; await waitFor(() => expect(mount.querySelectorAll('[role="radio"]')).toHaveLength(2), ); const firstRadio = mount.querySelector('[role="radio"]'); await act(async () => { initSwatches(); }); expect(mount.querySelectorAll('[role="radio"]')).toHaveLength(2); expect(mount.querySelector('[role="radio"]')).toBe(firstRadio); }); });