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("");
});
});