import { cleanup, fireEvent, render, renderHook, waitFor, } from "@testing-library/react"; import { afterEach, describe, expect, it, vi } from "vitest"; import SwatchGroup from "./SwatchGroup"; import { useSwatchSettings } from "../hooks/useSwatchSettings"; import { initQuantityButtons } from "../quantityButtons"; afterEach(() => { cleanup(); document.body.innerHTML = ""; vi.unstubAllGlobals(); }); describe("Free presentation without the extension bundle", () => { it("publishes the shared label size through the normalized typography variable", async () => { const select = document.createElement("select"); select.innerHTML = ''; document.body.append(select); const { container } = render( , ); await waitFor(() => expect(container.querySelector('[role="radio"]')).not.toBeNull(), ); const label = container.querySelector( '[role="radio"] [data-b3-wvs-swatch-text]', ); expect(label?.style.getPropertyValue("--b3-wvs-swatch-font-size")).toBe( "19px", ); }); it("applies mobile overrides and independent button sizing", () => { const settings = { use_mobile_layout: true, mobile_cutoff: 768, layout: "wrap", shape: "square", swatch_style: "underline", mobile_layout: "grid", mobile_shape: "circle", mobile_swatch_style: "background", mobile_grid_max_columns: 3, mobile_swatch_gap: 14, button_custom_sizing: true, button_swatch_width: 54, button_swatch_height: 42, }; const { result, rerender } = renderHook( ({ width }) => useSwatchSettings(settings, width), { initialProps: { width: 390 } }, ); expect(result.current).toMatchObject({ layout: "grid", shape: "circle", swatchStyle: "background", gridMaxColumns: 3, swatchGap: 14, buttonSwatchWidth: 54, buttonSwatchHeight: 42, }); rerender({ width: 1200 }); expect(result.current).toMatchObject({ layout: "wrap", shape: "square", swatchStyle: "underline", }); }); it("renders container styling and swatch-derived glow, and clears on reselect", async () => { const select = document.createElement("select"); select.innerHTML = ''; document.body.append(select); const { container } = render( , ); await waitFor(() => expect(container.querySelector('[role="radio"]')).not.toBeNull(), ); const radio = container.querySelector('[role="radio"]')!; expect( container.querySelector('[role="radiogroup"]')!.style .borderStyle, ).toBe("dashed"); expect(radio.classList.contains("b3-wvs-swatch-glow")).toBe(true); expect(radio.style.getPropertyValue("--b3-wvs-glow-color")).toBe("#ff0000"); fireEvent.click(radio); expect(select.value).toBe("red"); fireEvent.click(radio); expect(select.value).toBe(""); expect(radio.getAttribute("aria-checked")).toBe("false"); }); it("initializes quantity controls once and respects WooCommerce limits", () => { vi.stubGlobal("b3WvsData", { settings: { quantity_custom_buttons: true, quantity_style: "rounded", quantity_button_position: "both-sides", }, }); document.body.innerHTML = '
'; initQuantityButtons(); initQuantityButtons(); expect(document.querySelectorAll(".b3-wvs-qty-plus")).toHaveLength(1); const input = document.querySelector(".qty")!; const plus = document.querySelector(".b3-wvs-qty-plus")!; plus.click(); plus.click(); expect(input.value).toBe("3"); const minus = document.querySelector(".b3-wvs-qty-minus")!; minus.click(); minus.click(); minus.click(); expect(input.value).toBe("1"); }); it("uses custom quantity steps while honoring changed stock limits", () => { vi.stubGlobal("b3WvsData", { settings: { quantity_custom_buttons: true, quantity_style: "rounded", quantity_custom_limits: true, quantity_min: 2, quantity_max: 10, quantity_step: 2, }, }); document.body.innerHTML = '
'; initQuantityButtons(); const input = document.querySelector(".qty")!; const plus = document.querySelector(".b3-wvs-qty-plus")!; plus.click(); expect(input.value).toBe("4"); input.max = "5"; plus.click(); expect(input.value).toBe("4"); input.disabled = true; plus.click(); expect(input.value).toBe("4"); input.disabled = false; input.max = "0"; plus.click(); expect(input.value).toBe("0"); }); });