import { cleanup, render, screen } from "@solidjs/testing-library"; import { createSignal } from "solid-js"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; const { mockAnimate } = vi.hoisted(() => ({ mockAnimate: vi.fn().mockImplementation(() => ({ pause: vi.fn(), then: vi.fn((cb: () => void) => { cb(); return Promise.resolve(); }), })), })); vi.mock("animejs", () => ({ animate: mockAnimate, })); vi.mock("../../../../src/ts/utils/misc", () => ({ applyReducedMotion: vi.fn((duration: number) => duration), })); import { AnimeConditional } from "../../../../src/ts/components/common/anime/AnimeConditional"; describe("AnimeConditional", () => { beforeEach(() => { vi.clearAllMocks(); }); afterEach(() => { cleanup(); }); it("renders `then` content when `if` is truthy", () => { render(() => ( then} else={
else
} /> )); expect(screen.getByTestId("then-content")).toBeInTheDocument(); expect(screen.queryByTestId("else-content")).not.toBeInTheDocument(); }); it("renders `else` content when `if` is falsy", () => { render(() => ( then} else={
else
} /> )); expect(screen.queryByTestId("then-content")).not.toBeInTheDocument(); expect(screen.getByTestId("else-content")).toBeInTheDocument(); }); it("renders `else` content when `if` is null", () => { render(() => ( then} else={
else
} /> )); expect(screen.queryByTestId("then-content")).not.toBeInTheDocument(); expect(screen.getByTestId("else-content")).toBeInTheDocument(); }); it("switches reactively from `then` to `else`", () => { const [condition, setCondition] = createSignal(true); render(() => ( then} else={
else
} /> )); expect(screen.getByTestId("then-content")).toBeInTheDocument(); setCondition(false); expect(screen.queryByTestId("then-content")).not.toBeInTheDocument(); expect(screen.getByTestId("else-content")).toBeInTheDocument(); }); it("switches reactively from `else` to `then`", () => { const [condition, setCondition] = createSignal(false); render(() => ( then} else={
else
} /> )); expect(screen.getByTestId("else-content")).toBeInTheDocument(); setCondition(true); expect(screen.getByTestId("then-content")).toBeInTheDocument(); expect(screen.queryByTestId("else-content")).not.toBeInTheDocument(); }); it("supports `then` as a function and passes the truthy value", () => { const obj = { label: "hello" }; render(() => (
{value().label}
} /> )); expect(screen.getByTestId("fn-content")).toHaveTextContent("hello"); }); it("does not throw without `else` prop", () => { expect(() => { render(() => ( then} /> )); }).not.toThrow(); expect(screen.getByTestId("then-content")).toBeInTheDocument(); }); it("does not throw on mount/unmount", () => { const [show, setShow] = createSignal(true); expect(() => { render(() => ( then} else={
else
} /> )); }).not.toThrow(); expect(() => setShow(false)).not.toThrow(); expect(() => setShow(true)).not.toThrow(); }); describe("default animations (opacity fade)", () => { it("applies default opacity animate on `then` branch", () => { render(() => then} />); expect(mockAnimate).toHaveBeenCalledWith( expect.any(HTMLElement), expect.objectContaining({ opacity: 1, duration: 125 }), ); }); it("applies default opacity initial state on `then` branch", () => { render(() => then} />); // Initial call: opacity:0 with duration:0 expect(mockAnimate).toHaveBeenCalledWith( expect.any(HTMLElement), expect.objectContaining({ opacity: 0, duration: 0 }), ); }); }); describe("custom animeProps", () => { it("uses custom animate params when animeProps provided", () => { render(() => ( then} animeProps={{ initial: { opacity: 0, translateY: -10 }, animate: { opacity: 1, translateY: 0, duration: 400 }, exit: { opacity: 0, translateY: -10, duration: 200 }, }} /> )); expect(mockAnimate).toHaveBeenCalledWith( expect.any(HTMLElement), expect.objectContaining({ opacity: 1, translateY: 0, duration: 400 }), ); }); it("uses custom initial state when animeProps provided", () => { render(() => ( then} animeProps={{ initial: { opacity: 0, translateY: -10 }, animate: { opacity: 1, translateY: 0, duration: 400 }, }} /> )); // Initial state applied with duration:0 expect(mockAnimate).toHaveBeenCalledWith( expect.any(HTMLElement), expect.objectContaining({ opacity: 0, translateY: -10, duration: 0 }), ); }); }); it("exitBeforeEnter prop does not throw on condition change", () => { const [cond, setCond] = createSignal(true); expect(() => { render(() => ( then} else={
else
} /> )); }).not.toThrow(); expect(() => setCond(false)).not.toThrow(); }); });