UNPKG

vueless

Version:

Vue Styleless UI Component Library, powered by Tailwind CSS.

348 lines (276 loc) 9.33 kB
import { mount } from "@vue/test-utils"; import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; import USplitter from "../USplitter.vue"; function dispatchPointerDown(target: Element, clientX: number, clientY: number) { target.dispatchEvent( new PointerEvent("pointerdown", { bubbles: true, cancelable: true, clientX, clientY, pointerId: 1, pointerType: "mouse", }), ); } describe("USplitter", () => { beforeEach(() => { vi.useFakeTimers(); }); afterEach(() => { vi.restoreAllMocks(); localStorage.clear(); }); describe("Props", () => { it("ModelValue – initializes with provided sizes", () => { const modelValue = [30, 70]; const component = mount(USplitter, { props: { modelValue, }, slots: { "panel-1": "<div>Panel 1</div>", "panel-2": "<div>Panel 2</div>", }, }); const panels = component.findAll("[vl-key='panel']"); expect(panels).toHaveLength(2); expect(panels[0].attributes("style")).toMatch(/(^|;)\s*flex(-basis)?:[^;]*30%/); expect(panels[1].attributes("style")).toMatch(/(^|;)\s*flex(-basis)?:[^;]*70%/); }); it("Vertical – applies horizontal layout by default", () => { const component = mount(USplitter, { slots: { "panel-1": "<div>Panel 1</div>", "panel-2": "<div>Panel 2</div>", }, }); const wrapper = component.find("[vl-key='wrapper']"); expect(wrapper.attributes("class")).toContain("flex-row"); }); it("Vertical – applies vertical layout when true", () => { const component = mount(USplitter, { props: { vertical: true, }, slots: { "panel-1": "<div>Panel 1</div>", "panel-2": "<div>Panel 2</div>", }, }); const wrapper = component.find("[vl-key='wrapper']"); expect(wrapper.attributes("class")).toContain("flex-col"); }); it("GutterSize – applies custom gutter size", () => { const gutterSize = 10; const component = mount(USplitter, { props: { gutterSize, }, slots: { "panel-1": "<div>Panel 1</div>", "panel-2": "<div>Panel 2</div>", }, }); const gutter = component.find("[vl-key='gutter']"); expect(gutter.attributes("style")).toContain("--gutter-size: 10px"); }); it("Disabled – applies disabled state", () => { const component = mount(USplitter, { props: { disabled: true, }, slots: { "panel-1": "<div>Panel 1</div>", "panel-2": "<div>Panel 2</div>", }, }); const gutter = component.find("[vl-key='gutter']"); expect(gutter.attributes("class")).toContain("cursor-not-allowed"); expect(gutter.attributes("class")).toContain("opacity-50"); }); }); describe("Slots", () => { it("Panel slots – renders multiple panels", () => { const component = mount(USplitter, { slots: { "panel-1": "<div>Panel 1</div>", "panel-2": "<div>Panel 2</div>", "panel-3": "<div>Panel 3</div>", }, }); const panels = component.findAll("[vl-key='panel']"); expect(panels).toHaveLength(3); expect(component.text()).toContain("Panel 1"); expect(component.text()).toContain("Panel 2"); expect(component.text()).toContain("Panel 3"); }); it("Handle slot – renders custom handle", () => { const component = mount(USplitter, { slots: { "panel-1": "<div>Panel 1</div>", "panel-2": "<div>Panel 2</div>", handle: "<div class='custom-handle'>Custom</div>", }, }); expect(component.find(".custom-handle").exists()).toBe(true); expect(component.text()).toContain("Custom"); }); }); describe("Events", () => { it("Update:modelValue – emits when resizing", async () => { const component = mount(USplitter, { props: { modelValue: [50, 50], }, slots: { "panel-1": "<div>Panel 1</div>", "panel-2": "<div>Panel 2</div>", }, attachTo: document.body, }); const gutter = component.find("[vl-key='gutter']"); const wrapper = component.find("[vl-key='wrapper']"); vi.spyOn(wrapper.element, "getBoundingClientRect").mockReturnValue({ width: 1000, height: 500, top: 0, left: 0, right: 1000, bottom: 500, } as DOMRect); dispatchPointerDown(gutter.element, 500, 250); const pointerMoveEvent = new PointerEvent("pointermove", { clientX: 600, clientY: 250, }); document.dispatchEvent(pointerMoveEvent); await component.vm.$nextTick(); expect(component.emitted("update:modelValue")).toBeTruthy(); component.unmount(); }); it("Resize-start – emits when drag starts", async () => { const component = mount(USplitter, { slots: { "panel-1": "<div>Panel 1</div>", "panel-2": "<div>Panel 2</div>", }, attachTo: document.body, }); const gutter = component.find("[vl-key='gutter']"); dispatchPointerDown(gutter.element, 500, 250); expect(component.emitted("resize-start")).toBeTruthy(); component.unmount(); }); it("Resize-end – emits when drag ends", async () => { const component = mount(USplitter, { slots: { "panel-1": "<div>Panel 1</div>", "panel-2": "<div>Panel 2</div>", }, attachTo: document.body, }); const gutter = component.find("[vl-key='gutter']"); dispatchPointerDown(gutter.element, 500, 250); const pointerUpEvent = new PointerEvent("pointerup"); document.dispatchEvent(pointerUpEvent); await component.vm.$nextTick(); expect(component.emitted("resize-end")).toBeTruthy(); component.unmount(); }); }); describe("Interaction", () => { it("Gutter – renders between panels", () => { const component = mount(USplitter, { slots: { "panel-1": "<div>Panel 1</div>", "panel-2": "<div>Panel 2</div>", "panel-3": "<div>Panel 3</div>", }, }); const gutters = component.findAll("[vl-key='gutter']"); expect(gutters).toHaveLength(2); }); it("Keyboard – handles arrow key navigation", async () => { const component = mount(USplitter, { props: { modelValue: [50, 50], }, slots: { "panel-1": "<div>Panel 1</div>", "panel-2": "<div>Panel 2</div>", }, attachTo: document.body, }); const gutter = component.find("[vl-key='gutter']"); const wrapper = component.find("[vl-key='wrapper']"); vi.spyOn(wrapper.element, "getBoundingClientRect").mockReturnValue({ width: 1000, height: 500, top: 0, left: 0, right: 1000, bottom: 500, } as DOMRect); await gutter.trigger("keydown", { key: "ArrowRight", }); await component.vm.$nextTick(); expect(component.emitted("update:modelValue")).toBeTruthy(); component.unmount(); }); it("Double click – resets to equal sizes", async () => { const component = mount(USplitter, { props: { modelValue: [30, 70], }, slots: { "panel-1": "<div>Panel 1</div>", "panel-2": "<div>Panel 2</div>", }, }); const gutter = component.find("[vl-key='gutter']"); await gutter.trigger("dblclick"); const emitted = component.emitted("update:modelValue"); expect(emitted).toBeTruthy(); if (!emitted) { throw new Error("expected update:modelValue"); } const lastEmit = emitted[emitted.length - 1][0] as number[]; expect(lastEmit[0]).toBeCloseTo(50, 0); expect(lastEmit[1]).toBeCloseTo(50, 0); }); }); describe("Accessibility", () => { it("ARIA – gutter has proper ARIA attributes", () => { const component = mount(USplitter, { props: { modelValue: [40, 60], }, slots: { "panel-1": "<div>Panel 1</div>", "panel-2": "<div>Panel 2</div>", }, }); const gutter = component.find("[vl-key='gutter']"); expect(gutter.attributes("role")).toBe("separator"); expect(gutter.attributes("aria-orientation")).toBe("horizontal"); expect(gutter.attributes("aria-valuenow")).toBe("40"); expect(gutter.attributes("aria-valuemin")).toBe("0"); expect(gutter.attributes("aria-valuemax")).toBe("100"); expect(gutter.attributes("tabindex")).toBe("0"); }); }); describe("Exposed refs", () => { it("WrapperRef – exposes wrapper element ref", () => { const component = mount(USplitter, { slots: { "panel-1": "<div>Panel 1</div>", "panel-2": "<div>Panel 2</div>", }, }); expect(component.vm.wrapperRef).toBeDefined(); expect(component.vm.wrapperRef instanceof HTMLDivElement).toBe(true); }); }); });