import { cleanup, fireEvent, render, waitFor } from "@testing-library/react"; import { afterEach, describe, expect, it, vi } from "vitest"; import FlowLayout from "./FlowLayout"; import SwatchGroup, { type SwatchData } from "./SwatchGroup"; afterEach(() => { cleanup(); document.body.querySelectorAll("select").forEach((select) => select.remove()); vi.unstubAllGlobals(); }); function stubMotion({ hover, reduced }: { hover: boolean; reduced: boolean }) { vi.stubGlobal( "matchMedia", vi.fn((query: string) => ({ matches: query.includes("prefers-reduced-motion") ? reduced : hover, media: query, addEventListener: vi.fn(), removeEventListener: vi.fn(), addListener: vi.fn(), removeListener: vi.fn(), })), ); } const items = ["Blue", "Green", "Red"].map((label) => ({ key: label, content: , })); describe("FlowLayout", () => { it("powers the Free SwatchGroup Flow branch", async () => { stubMotion({ hover: true, reduced: false }); const select = document.createElement("select"); select.name = "attribute_pa_color"; for (const value of ["", "blue", "green", "red"]) { const option = document.createElement("option"); option.value = value; select.append(option); } document.body.append(select); const swatches: Record = Object.fromEntries( ["blue", "green", "red"].map((value) => [ value, { type: "color", color: value, label: value }, ]), ); const { container } = render( , ); const wrappers = await waitFor(() => { const result = container.querySelectorAll( '[data-flow-item="true"]', ); expect(result).toHaveLength(3); return result; }); fireEvent.mouseEnter(wrappers[1]); await waitFor(() => expect(wrappers[1].style.transform).toContain("scale(1.15)"), ); expect(wrappers[0].style.transform).toContain("rotateY(-8deg)"); }); it("applies coverflow transforms to the active item and its neighbors", async () => { stubMotion({ hover: true, reduced: false }); const { container } = render(); const wrappers = container.querySelectorAll( '[data-flow-item="true"]', ); fireEvent.mouseEnter(wrappers[1]); await waitFor(() => expect(wrappers[1].style.transform).toContain("scale(1.15)"), ); expect(wrappers[0].style.transform).toContain("rotateY(-8deg)"); expect(wrappers[2].style.transform).toContain("rotateY(8deg)"); fireEvent.mouseLeave(wrappers[1]); expect(wrappers[0].style.transform).toBe(""); fireEvent.focus(wrappers[0].querySelector("button")!); expect(wrappers[0].style.transform).toContain("scale(1.15)"); }); it("keeps Flow static when reduced motion is requested", async () => { stubMotion({ hover: true, reduced: true }); const { container } = render(); const wrappers = container.querySelectorAll( '[data-flow-item="true"]', ); fireEvent.mouseEnter(wrappers[1]); await waitFor(() => expect(wrappers[1].style.transform).toBe("")); expect(wrappers[0].style.transform).toBe(""); expect(wrappers[2].style.transform).toBe(""); }); it("keeps Flow static on coarse-pointer devices", async () => { stubMotion({ hover: false, reduced: false }); const { container } = render(); const wrappers = container.querySelectorAll( '[data-flow-item="true"]', ); fireEvent.mouseEnter(wrappers[1]); await waitFor(() => expect(wrappers[1].style.transform).toBe("")); expect(wrappers[0].style.transform).toBe(""); }); });