import { act } from "react"; import { createRoot } from "react-dom/client"; import { afterEach, describe, expect, it } from "vitest"; import { AnimatedPreviewBox } from "."; const REDUCED_MOTION_QUERY = "(prefers-reduced-motion: reduce)"; function stubReducedMotion(reduce: boolean): () => void { const original = window.matchMedia; Object.defineProperty(window, "matchMedia", { configurable: true, writable: true, value: (query: string) => ({ matches: reduce && query === REDUCED_MOTION_QUERY, media: query, onchange: null, addEventListener: () => {}, removeEventListener: () => {}, addListener: () => {}, removeListener: () => {}, dispatchEvent: () => false, }) as unknown as MediaQueryList, }); return () => { Object.defineProperty(window, "matchMedia", { configurable: true, writable: true, value: original, }); }; } describe("AnimatedPreviewBox", () => { let container: HTMLDivElement | null = null; afterEach(() => { container?.remove(); container = null; }); it.each(["scale", "lift"])( "drops the %s hover/active utilities under prefers-reduced-motion but keeps focus handling", (animation) => { const restore = stubReducedMotion(true); container = document.createElement("div"); document.body.appendChild(container); const root = createRoot(container); act(() => { root.render( Preview , ); }); const box = container.querySelector("button > div"); expect(box?.className).not.toContain("group-hover:test-hover-class"); expect(box?.className).not.toContain("group-active:test-active-class"); // Normal focus affordance is untouched. expect(container.querySelector("button")?.className).toContain( "bwvs:focus-visible:ring-2", ); act(() => root.unmount()); restore(); }, ); it("does not apply the keyframe class while hovered under prefers-reduced-motion", () => { const restore = stubReducedMotion(true); container = document.createElement("div"); document.body.appendChild(container); const root = createRoot(container); act(() => { root.render( Preview , ); }); const button = container.querySelector("button"); act(() => { button?.dispatchEvent(new MouseEvent("mouseover", { bubbles: true })); }); expect( container .querySelector("button > div") ?.classList.contains("b3-wvs-animate-swatch-bounce"), ).toBe(false); act(() => root.unmount()); restore(); }); it("keeps scale/lift hover utilities when motion is not reduced", () => { const restore = stubReducedMotion(false); container = document.createElement("div"); document.body.appendChild(container); const root = createRoot(container); act(() => { root.render( Preview , ); }); const button = container.querySelector("button"); expect(button?.className).toContain("bwvs:h-12"); expect(button?.className).toContain("bwvs:w-12"); expect(button?.className).toContain("bwvs:flex-none"); expect(container.querySelector("button > div")?.className).toContain( "group-hover:test-hover-class", ); act(() => root.unmount()); restore(); }); it.each([ [false, false], [true, true], ])("gates active classes with animateOnHover=%s", (enabled, expected) => { container = document.createElement("div"); document.body.appendChild(container); const root = createRoot(container); act(() => { root.render( Preview , ); }); expect( container .querySelector("button > div") ?.classList.contains("test-active-class"), ).toBe(expected); act(() => root.unmount()); }); });