vueless
Version:
Vue Styleless UI Component Library, powered by Tailwind CSS.
572 lines (468 loc) • 14.8 kB
text/typescript
import { mount, flushPromises } from "@vue/test-utils";
import { describe, it, expect } from "vitest";
import { nextTick, ref } from "vue";
import UCollapsible from "../UCollapsible.vue";
import type { Props } from "../types";
import type { UnknownObject } from "../../types";
function mountCollapsible(options: UnknownObject = {}) {
return mount(UCollapsible, options);
}
describe("UCollapsible.vue", () => {
describe("Props", () => {
it("Model Value – controls opened state when provided", async () => {
const open = ref(false);
const component = mountCollapsible({
props: {
open: open.value,
dataTest: "test",
"onUpdate:open": (value: boolean) => {
open.value = value;
component.setProps({ open: value });
},
},
slots: {
default: "Trigger",
content: "Content",
},
});
expect(component.find('[data-test="test-content"]').exists()).toBe(false);
await component.find('[data-test="test"]').trigger("click");
await nextTick();
expect(component.emitted("update:open")).toBeTruthy();
expect(component.emitted("update:open")![0][0]).toBe(true);
await component.setProps({ open: true });
await nextTick();
expect(component.find('[data-test="test-content"]').exists()).toBe(true);
});
it("Model Value – works independently when not provided", async () => {
const component = mountCollapsible({
props: {
dataTest: "test",
},
slots: {
default: "Trigger",
content: "Content",
},
});
expect(component.find('[data-test="test-content"]').exists()).toBe(false);
await component.find('[data-test="test"]').trigger("click");
await nextTick();
await flushPromises();
expect(component.find('[data-test="test-content"]').exists()).toBe(true);
});
it("YPosition – applies correct position class for top", () => {
const component = mountCollapsible({
props: {
yPosition: "top" as Props["yPosition"],
open: true,
dataTest: "test",
},
slots: {
default: "Trigger",
content: "Content",
},
});
const content = component.find('[data-test="test-content"]');
expect(content.attributes("class")).toContain("bottom-full");
expect(content.attributes("class")).toContain("mb-1");
});
it("YPosition – applies correct position class for bottom", () => {
const component = mountCollapsible({
props: {
yPosition: "bottom" as Props["yPosition"],
open: true,
dataTest: "test",
},
slots: {
default: "Trigger",
content: "Content",
},
});
const content = component.find('[data-test="test-content"]');
expect(content.attributes("class")).toContain("top-full");
expect(content.attributes("class")).toContain("mt-1");
});
it("XPosition – applies correct position class for left", () => {
const component = mountCollapsible({
props: {
xPosition: "left" as Props["xPosition"],
open: true,
dataTest: "test",
},
slots: {
default: "Trigger",
content: "Content",
},
});
const content = component.find('[data-test="test-content"]');
expect(content.attributes("class")).toContain("left-0");
});
it("XPosition – applies correct position class for right", () => {
const component = mountCollapsible({
props: {
xPosition: "right" as Props["xPosition"],
open: true,
dataTest: "test",
},
slots: {
default: "Trigger",
content: "Content",
},
});
const content = component.find('[data-test="test-content"]');
expect(content.attributes("class")).toContain("right-0");
});
it("Absolute – applies absolute positioning when true", () => {
const component = mountCollapsible({
props: {
absolute: true,
open: true,
dataTest: "test",
},
slots: {
default: "Trigger",
content: "Content",
},
});
const content = component.find('[data-test="test-content"]');
expect(content.attributes("class")).toContain("absolute");
});
it("Absolute – does not apply absolute positioning when false", () => {
const component = mountCollapsible({
props: {
absolute: false,
open: true,
dataTest: "test",
},
slots: {
default: "Trigger",
content: "Content",
},
});
const content = component.find('[data-test="test-content"]');
expect(content.attributes("class")).not.toContain("absolute");
});
it("Disabled – prevents opening when disabled", async () => {
const component = mountCollapsible({
props: {
disabled: true,
dataTest: "test",
},
slots: {
default: "Trigger",
content: "Content",
},
});
await component.find('[data-test="test"]').trigger("click");
await nextTick();
expect(component.find('[data-test="test-content"]').exists()).toBe(false);
});
it("Disabled – applies cursor-not-allowed class", () => {
const component = mountCollapsible({
props: {
disabled: true,
dataTest: "test",
},
slots: {
default: "Trigger",
content: "Content",
},
});
const wrapper = component.find('[data-test="test"]');
expect(wrapper.attributes("class")).toContain("cursor-not-allowed");
});
it("CloseOnOutside – closes when clicking outside", async () => {
const component = mountCollapsible({
props: {
closeOnOutside: true,
open: true,
dataTest: "test",
},
slots: {
default: "Trigger",
content: "Content",
},
attachTo: document.body,
});
expect(component.find('[data-test="test-content"]').exists()).toBe(true);
document.body.click();
await nextTick();
expect(component.emitted("close")).toBeTruthy();
component.unmount();
});
it("CloseOnContent – closes when clicking content", async () => {
const component = mountCollapsible({
props: {
closeOnContent: true,
open: true,
dataTest: "test",
},
slots: {
default: "Trigger",
content: "Content",
},
});
await component.find('[data-test="test-content"]').trigger("click");
await nextTick();
expect(component.emitted("close")).toBeTruthy();
});
it("CloseOnContent – does not close when false", async () => {
const component = mountCollapsible({
props: {
closeOnContent: false,
open: true,
dataTest: "test",
},
slots: {
default: "Trigger",
content: "Content",
},
});
await component.find('[data-test="test-content"]').trigger("click");
await nextTick();
expect(component.find('[data-test="test-content"]').exists()).toBe(true);
});
it("Id – applies custom id when provided", () => {
const customId = "custom-collapsible-id";
const component = mountCollapsible({
props: {
id: customId,
dataTest: "test",
},
slots: {
default: "Trigger",
content: "Content",
},
});
const wrapper = component.find('[data-test="test"]');
expect(wrapper.attributes("id")).toBe(customId);
});
it("DataTest – applies custom data-test attribute", () => {
const dataTest = "custom-test";
const component = mountCollapsible({
props: {
dataTest,
},
slots: {
default: "Trigger",
content: "Content",
},
});
expect(component.find(`[data-test="${dataTest}"]`).exists()).toBe(true);
});
});
describe("Slots", () => {
it("Default – renders trigger content", () => {
const triggerContent = "Click Me";
const component = mountCollapsible({
slots: {
default: triggerContent,
},
});
expect(component.text()).toContain(triggerContent);
});
it("Default – exposes opened state to slot", async () => {
const component = mountCollapsible({
props: {
dataTest: "test",
},
slots: {
default: `<template #default="{ opened }">
<div class="trigger">{{ opened ? 'Opened' : 'Closed' }}</div>
</template>`,
},
});
expect(component.find(".trigger").text()).toBe("Closed");
await component.find('[data-test="test"]').trigger("click");
await nextTick();
await flushPromises();
expect(component.find(".trigger").text()).toBe("Opened");
});
it("Content – renders collapsible content when opened", () => {
const contentText = "Collapsible Content";
const component = mountCollapsible({
props: {
open: true,
},
slots: {
default: "Trigger",
content: contentText,
},
});
expect(component.text()).toContain(contentText);
});
it("Content – exposes opened state to slot", () => {
const component = mountCollapsible({
props: {
open: true,
},
slots: {
default: "Trigger",
content: `<template #content="{ opened }">
<div class="content-state">{{ opened ? 'Open' : 'Closed' }}</div>
</template>`,
},
});
expect(component.find(".content-state").text()).toBe("Open");
});
});
describe("Events", () => {
it("Update:open – emits when toggling", async () => {
const component = mountCollapsible({
props: {
open: false,
dataTest: "test",
},
slots: {
default: "Trigger",
content: "Content",
},
});
await component.find('[data-test="test"]').trigger("click");
await nextTick();
expect(component.emitted("update:open")).toBeTruthy();
expect(component.emitted("update:open")![0][0]).toBe(true);
});
it("Open – emits when collapsible opens", async () => {
const component = mountCollapsible({
props: {
dataTest: "test",
},
slots: {
default: "Trigger",
content: "Content",
},
});
await component.find('[data-test="test"]').trigger("click");
await nextTick();
await flushPromises();
expect(component.emitted("open")).toBeTruthy();
});
it("Close – emits when collapsible closes", async () => {
const component = mountCollapsible({
props: {
open: true,
dataTest: "test",
},
slots: {
default: "Trigger",
content: "Content",
},
});
await component.find('[data-test="test"]').trigger("click");
await nextTick();
await flushPromises();
expect(component.emitted("close")).toBeTruthy();
});
});
describe("Exposed Methods", () => {
it("wrapperRef – exposes wrapper element reference", () => {
const component = mountCollapsible({
slots: {
default: "Trigger",
content: "Content",
},
});
expect(component.vm.wrapperRef).toBeDefined();
expect(component.vm.wrapperRef).toBeInstanceOf(HTMLDivElement);
});
it("show – opens the collapsible", async () => {
const component = mountCollapsible({
props: {
dataTest: "test",
},
slots: {
default: "Trigger",
content: "Content",
},
});
component.vm.show();
await nextTick();
await flushPromises();
expect(component.find('[data-test="test-content"]').exists()).toBe(true);
expect(component.emitted("open")).toBeTruthy();
});
it("show – does not open when disabled", async () => {
const component = mountCollapsible({
props: {
disabled: true,
dataTest: "test",
},
slots: {
default: "Trigger",
content: "Content",
},
});
component.vm.show();
await nextTick();
expect(component.find('[data-test="test-content"]').exists()).toBe(false);
});
it("hide – closes the collapsible", async () => {
const component = mountCollapsible({
props: {
open: true,
dataTest: "test",
},
slots: {
default: "Trigger",
content: "Content",
},
});
expect(component.find('[data-test="test-content"]').exists()).toBe(true);
component.vm.hide();
await nextTick();
expect(component.emitted("close")).toBeTruthy();
});
it("toggle – toggles the collapsible state", async () => {
const component = mountCollapsible({
props: {
dataTest: "test",
},
slots: {
default: "Trigger",
content: "Content",
},
});
component.vm.toggle();
await nextTick();
await flushPromises();
expect(component.find('[data-test="test-content"]').exists()).toBe(true);
component.vm.toggle();
await nextTick();
await flushPromises();
expect(component.find('[data-test="test-content"]').exists()).toBe(false);
});
it("toggle – does not toggle when disabled", async () => {
const component = mountCollapsible({
props: {
disabled: true,
dataTest: "test",
},
slots: {
default: "Trigger",
content: "Content",
},
});
component.vm.toggle();
await nextTick();
expect(component.find('[data-test="test-content"]').exists()).toBe(false);
});
it("isOpened – reflects the current opened state", async () => {
const component = mountCollapsible({
slots: {
default: "Trigger",
content: "Content",
},
});
expect(component.vm.isOpened).toBe(false);
component.vm.show();
await nextTick();
await flushPromises();
expect(component.vm.isOpened).toBe(true);
component.vm.hide();
await nextTick();
await flushPromises();
expect(component.vm.isOpened).toBe(false);
});
});
});