import { fireEvent, render } from "@testing-library/vue"; import { describe, expect, it } from "vitest"; import DsLogicTree from "../src/components/data/DsLogicTree.vue"; import DsSortableList from "../src/components/data/DsSortableList.vue"; import type { DsLogicGroup, DsSortableItem } from "../src/types"; const sortableItems: DsSortableItem[] = [ { id: "one", label: "Primero" }, { id: "two", label: "Segundo" }, { id: "three", label: "Tercero" }, ]; const emptyTree: DsLogicGroup = { id: "root", type: "group", operator: "and", children: [], }; const fields = [ { label: "Estado", value: "status" }, { label: "Plan", value: "plan" }, ]; describe("data tools", () => { it("reorders items with drag-and-drop and emits the movement", async () => { const view = render(DsSortableList, { props: { modelValue: sortableItems, label: "Prioridades" }, }); const items = view.getAllByRole("listitem"); await fireEvent.dragStart(items[0] as HTMLElement); await fireEvent.dragOver(items[2] as HTMLElement); await fireEvent.drop(items[2] as HTMLElement); const updates = view.emitted()["update:modelValue"] as unknown[][] | undefined; const reordered = updates?.at(-1)?.[0] as DsSortableItem[] | undefined; expect(reordered?.map((item) => item.id)).toEqual(["two", "three", "one"]); expect(view.emitted().reorder?.at(-1)).toEqual([ expect.objectContaining({ from: 0, to: 2 }), ]); }); it("offers buttons as an accessible alternative to dragging", async () => { const view = render(DsSortableList, { props: { modelValue: sortableItems, label: "Prioridades" }, }); await fireEvent.click( view.getByRole("button", { name: "Mover abajo: Primero" }), ); const updates = view.emitted()["update:modelValue"] as unknown[][] | undefined; const reordered = updates?.at(-1)?.[0] as DsSortableItem[] | undefined; expect(reordered?.map((item) => item.id)).toEqual(["two", "one", "three"]); expect(view.getByRole("status").textContent).toContain( "Primero, movido a la posición 2 de 3.", ); }); it("adds a serializable condition to a logic tree", async () => { const view = render(DsLogicTree, { props: { modelValue: emptyTree, fields }, }); await fireEvent.click( view.getByRole("button", { name: "Añadir condición" }), ); const updates = view.emitted()["update:modelValue"] as unknown[][] | undefined; const tree = updates?.at(-1)?.[0] as DsLogicGroup | undefined; expect(tree?.children).toHaveLength(1); expect(tree?.children[0]).toEqual( expect.objectContaining({ type: "condition", field: "status", comparison: "equals", value: "", }), ); expect(view.emitted().change?.at(-1)).toEqual([tree]); }); it("updates operators and removes nested rules", async () => { const tree: DsLogicGroup = { ...emptyTree, children: [ { id: "status", type: "condition", field: "status", comparison: "equals", value: "active", }, ], }; const operatorView = render(DsLogicTree, { props: { modelValue: tree, fields }, }); await fireEvent.update( operatorView.getByLabelText("Operador lógico"), "or", ); const operatorUpdates = operatorView.emitted()["update:modelValue"] as unknown[][] | undefined; expect( (operatorUpdates?.at(-1)?.[0] as DsLogicGroup | undefined)?.operator, ).toBe("or"); operatorView.unmount(); const removeView = render(DsLogicTree, { props: { modelValue: tree, fields }, }); await fireEvent.click(removeView.getByRole("button", { name: "Eliminar" })); const removeUpdates = removeView.emitted()["update:modelValue"] as unknown[][] | undefined; const updated = removeUpdates?.at(-1)?.[0] as DsLogicGroup | undefined; expect(updated?.children).toEqual([]); }); });