import type { FieldMetadata, SavedFilter } from "@olenbetong/appframe-core"; import { render, screen, waitFor } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { beforeEach, describe, expect, it, vi } from "vitest"; const save = vi.fn(async () => undefined); const remove = vi.fn(async () => undefined); const rename = vi.fn(async () => undefined); const setCrossDomain = vi.fn(async () => undefined); const setNamedFilter = vi.fn(); const parseFilterString = vi.fn(async () => null); let savedFilters: SavedFilter[] = []; vi.mock("@olenbetong/appframe-react", async (importOriginal) => ({ ...(await importOriginal>()), setNamedFilter: (...args: unknown[]) => setNamedFilter(...args), useSavedFilters: () => ({ filters: savedFilters, mine: savedFilters.filter((filter) => filter.createdByUser), shared: savedFilters.filter((filter) => !filter.createdByUser), loading: false, error: null, refresh: vi.fn(), save, rename, remove, setCrossDomain, }), useFilterConversion: () => ({ filterString: "[PersonID] Like '%a%'", isConverting: false, error: null, parseFilterString, }), })); const { FilterBuilder } = await import("./FilterBuilder.js"); const FIELDS: FieldMetadata[] = [ { name: "PersonID", caption: "Person ID", type: "string", nullable: true }, { name: "Age", caption: "Age", type: "number" }, ]; function savedFilter(overrides: Partial & Pick): SavedFilter { return { primKey: `pk-${overrides.filterId}`, criteria: "[PersonID] Like '%a%'", dbObjectId: "aviw_Test_View", accessLevel: "Manager", createdByUser: true, createdBy: "bvh", domain: "OB", crossDomain: false, isPersonallyShared: false, hideCriteria: false, headerText: null, comment: null, parameters: null, reportTitle: null, created: null, updated: null, ...overrides, }; } function renderBuilder(props: Record = {}) { return render(); } describe("FilterBuilder", () => { beforeEach(() => { vi.clearAllMocks(); savedFilters = [savedFilter({ filterId: 1, name: "Agder" })]; }); it("renders the saved filters beside the editor", () => { renderBuilder(); expect(screen.getByRole("button", { name: "New Filter" })).toBeTruthy(); expect(screen.getByRole("button", { name: "Agder" })).toBeTruthy(); expect(screen.getByLabelText("Add condition")).toBeTruthy(); }); it("disables save and share until a filter is selected", () => { renderBuilder(); expect(screen.getByRole("button", { name: "Sharing..." }).hasAttribute("disabled")).toBe(true); expect(screen.getByRole("button", { name: "Save" }).hasAttribute("disabled")).toBe(true); }); it("disables save as while the filter is empty", () => { renderBuilder(); expect(screen.getByRole("button", { name: "Save as" }).hasAttribute("disabled")).toBe(true); }); it("parses the criteria of a selected filter back into the tree", async () => { renderBuilder(); await userEvent.click(screen.getByRole("button", { name: "Agder" })); expect(parseFilterString).toHaveBeenCalledWith("[PersonID] Like '%a%'"); }); it("applies the pruned filter to the data object", async () => { let dataObject = {} as never; renderBuilder({ dataObject, defaultValue: { type: "group", mode: "and", items: [{ type: "expression", column: "PersonID", operator: "like", value: "a", valueType: "string" }], }, }); await userEvent.click(screen.getByRole("button", { name: "OK" })); expect(setNamedFilter).toHaveBeenCalledWith( dataObject, "filterBuilder", expect.objectContaining({ type: "group" }), { type: "filterObject" }, ); }); it("reports an empty filter as null", async () => { let onApply = vi.fn(); renderBuilder({ onApply }); await userEvent.click(screen.getByRole("button", { name: "OK" })); expect(onApply).toHaveBeenCalledWith(null, "[PersonID] Like '%a%'"); }); it("saves under a new name and replaces a filter that already uses it", async () => { renderBuilder({ defaultValue: { type: "group", mode: "and", items: [{ type: "expression", column: "PersonID", operator: "like", value: "a", valueType: "string" }], }, }); await userEvent.click(screen.getByRole("button", { name: "Save as" })); await userEvent.type(screen.getByRole("textbox", { name: "Filter name" }), "Agder"); await userEvent.click(screen.getByRole("button", { name: "Replace" })); await waitFor(() => expect(save).toHaveBeenCalledWith( expect.objectContaining({ filterId: 1, name: "Agder", criteria: "[PersonID] Like '%a%'" }), ), ); }); });