import { cleanup, render, renderHook, screen } from "@testing-library/react"; import { afterEach, describe, expect, it } from "vitest"; import { z } from "zod"; import * as filterExports from "../index.js"; import { FilterBuilder, FilterSphereProvider, FilterThemeProvider, createFilterTheme, presetTheme, useFilterSphere, useView, } from "../index.js"; const DefaultThemeFilter = () => { const { context } = useFilterSphere({ schema: z.object({ name: z.string() }), }); return ( ); }; afterEach(() => { cleanup(); }); describe("theme boundary", () => { it("requires an explicit theme provider for theme hooks", () => { expect(() => renderHook(() => useView("templates"))).toThrow( "useFilterTheme must be used within FilterThemeProvider", ); }); it("FilterSphereProvider supplies the preset theme when theme is omitted", () => { render(); expect(screen.getByRole("button", { name: "And" })).toBeTruthy(); expect(screen.getByRole("button", { name: "Add Rule" })).toBeTruthy(); expect(screen.getByRole("button", { name: "Add Group" })).toBeTruthy(); }); it("preserves an outer FilterThemeProvider when FilterSphereProvider theme is omitted", () => { const outerTheme = createFilterTheme({ components: { Button: ({ children, ...props }) => ( ), }, }); const OuterThemeFilter = () => { const { context } = useFilterSphere({ schema: z.object({ name: z.string() }), }); return ( ); }; render(); expect( screen .getByRole("button", { name: "And" }) .getAttribute("data-custom-theme"), ).toBe("outer"); }); }); describe("preset theme", () => { it("does not expose a duplicate preset theme parts alias", () => { expect("presetThemeParts" in filterExports).toBe(false); }); it("createFilterTheme uses presetTheme as defaults", () => { const theme = createFilterTheme({}); expect(theme.primitives.select).toBe(presetTheme.primitives.select); expect(theme.components.Select).toBe(presetTheme.components.Select); expect(theme.templates.FilterSelect).toBe( presetTheme.templates.FilterSelect, ); expect(theme.dataInputViews).toEqual(presetTheme.dataInputViews); }); });