vueless
Version:
Vue Styleless UI Component Library, powered by Tailwind CSS.
340 lines (268 loc) • 9.97 kB
text/typescript
import { mount } from "@vue/test-utils";
import { describe, it, expect } from "vitest";
import UTabs from "../UTabs.vue";
import UTab from "../../ui.navigation-tab/UTab.vue";
import UButton from "../../ui.button/UButton.vue";
import type { Props, UTabsOption } from "../types.ts";
describe("UTabs.vue", () => {
// Global options definition
const options: UTabsOption[] = [
{ value: "tab1", label: "Tab 1" },
{ value: "tab2", label: "Tab 2" },
{ value: "tab3", label: "Tab 3" },
];
// Props tests
describe("Props", () => {
// ModelValue prop
it("correctly sets the selected tab", () => {
const modelValue = "tab2";
const expectedActiveClass = "border-primary";
const component = mount(UTabs, {
props: {
options,
modelValue,
},
});
// Find all UTab components
const tabs = component.findAllComponents(UTab);
// Check that the correct tab is active
expect(tabs.length).toBe(options.length);
// The second tab should be active
const activeTab = tabs[1];
expect(activeTab.classes()).toContain(expectedActiveClass);
});
// Options prop
it("renders the correct number of tabs from options", () => {
const component = mount(UTabs, {
props: {
options,
},
});
// Find all UTab components
const tabs = component.findAllComponents(UTab);
// Check that the correct number of tabs is rendered
expect(tabs.length).toBe(options.length);
// Check that the tabs have the correct labels
options.forEach((option, index) => {
expect(tabs[index].text()).toBe(option.label);
});
});
// Size prop
it("applies the correct size to tabs", () => {
const sizes = ["2xs", "xs", "sm", "md", "lg", "xl"];
sizes.forEach((size) => {
const component = mount(UTabs, {
props: {
options: [{ value: "tab1", label: "Tab 1" }],
size: size as Props["size"],
},
});
// Find the UTab component
const tab = component.findComponent(UTab);
// Find the UButton inside the UTab
const button = tab.findComponent(UButton);
// Check that the button has the correct size
expect(button.props("size")).toBe(size);
});
});
// Scrollable prop
it("applies scrollable class when scrollable prop is true", () => {
const scrollable = true;
const component = mount(UTabs, {
props: {
options,
scrollable,
},
});
// Find the tabs container
const tabsContainer = component.find(`[vl-key="tabs"]`);
// Check that the container has the scrollable class
expect(tabsContainer.classes()).toContain("scroll-smooth");
});
// Scroll buttons
it("shows scroll buttons when scrollable and content overflows", async () => {
const manyOptions: UTabsOption[] = Array.from({ length: 10 }, (_, i) => ({
value: `tab${i}`,
label: `Tab ${i}`,
}));
const component = mount(UTabs, {
props: {
options: manyOptions,
scrollable: true,
},
});
// Mock the scroll position to show both arrows
const scrollContainer = component.find(`[vl-key="tabs"]`).element;
Object.defineProperty(scrollContainer, "scrollLeft", { value: 10 });
Object.defineProperty(scrollContainer, "scrollWidth", { value: 1000 });
Object.defineProperty(scrollContainer, "clientWidth", { value: 500 });
// Trigger scroll event
await component.find("[vl-key='tabs']").trigger("scroll");
// Both arrows should be visible
const buttons = component.findAllComponents(UButton);
// Check that at least two buttons are rendered
expect(buttons.length).toBeGreaterThanOrEqual(2);
// Find the buttons with the correct icons
const prevButton = buttons.find((button) => button.props("icon") === "chevron_left");
const nextButton = buttons.find((button) => button.props("icon") === "chevron_right");
expect(prevButton).toBeDefined();
expect(nextButton).toBeDefined();
});
// Block prop
it("provides block value to tabs", () => {
const block = true;
const component = mount(UTabs, {
props: {
options: [{ value: "tab1", label: "Tab 1" }],
block,
},
});
// Find the UTab component
const tab = component.findComponent(UTab);
// Find the UButton inside the UTab
const button = tab.findComponent(UButton);
// Check that the button has the block prop
expect(button.props("block")).toBe(block);
});
// Square prop
it("provides square value to tabs", () => {
const square = true;
const component = mount(UTabs, {
props: {
options: [{ value: "tab1", label: "Tab 1" }],
square,
},
});
// Find the UTab component
const tab = component.findComponent(UTab);
// Find the UButton inside the UTab
const button = tab.findComponent(UButton);
// Check that the button has the square prop
expect(button.props("square")).toBe(square);
});
// DataTest prop
it("applies the correct data-test attribute", () => {
const dataTest = "test-tabs";
const singleOption = [options[0]];
const component = mount(UTabs, {
props: {
options: singleOption,
dataTest,
},
});
// Find the tabs container
const tabsContainer = component.find(`[data-test="${dataTest}"]`);
// Check that the container has the data-test attribute
expect(tabsContainer.exists()).toBe(true);
// Check that the tab has the correct data-test attribute
const tab = component.find(`[data-test="${dataTest}-item-0"]`);
expect(tab.exists()).toBe(true);
});
});
// Slots tests
describe("Slots", () => {
// Default slot
it("renders content from default slot", () => {
const slotContent = "Custom Tabs";
const slotClass = "custom-tabs";
const component = mount(UTabs, {
slots: {
default: `<div class="${slotClass}">${slotContent}</div>`,
},
});
expect(component.find(`.${slotClass}`).exists()).toBe(true);
expect(component.find(`.${slotClass}`).text()).toBe(slotContent);
});
// Prev slot
it("renders content from prev slot when scrollable", async () => {
const slotContent = "Prev";
const slotClass = "prev-content";
const dataTest = "test-tabs";
const manyOptions: UTabsOption[] = Array.from({ length: 10 }, (_, i) => ({
value: `tab${i}`,
label: `Tab ${i}`,
}));
const component = mount(UTabs, {
props: {
options: manyOptions,
scrollable: true,
dataTest,
},
slots: {
prev: `<div class="${slotClass}">${slotContent}</div>`,
},
});
// Mock the scroll position to show left arrow
const scrollContainer = component.find(`[vl-key="tabs"]`).element;
Object.defineProperty(scrollContainer, "scrollLeft", { value: 10 });
Object.defineProperty(scrollContainer, "scrollWidth", { value: 1000 });
Object.defineProperty(scrollContainer, "clientWidth", { value: 500 });
// Trigger scroll event
await component.find("[vl-key='tabs']").trigger("scroll");
// Now the left arrow should be visible
expect(component.find(`.${slotClass}`).exists()).toBe(true);
expect(component.find(`.${slotClass}`).text()).toBe(slotContent);
});
// Next slot
it("renders content from next slot when scrollable", async () => {
const slotContent = "Next";
const slotClass = "next-content";
const dataTest = "test-tabs";
const manyOptions: UTabsOption[] = Array.from({ length: 10 }, (_, i) => ({
value: `tab${i}`,
label: `Tab ${i}`,
}));
const component = mount(UTabs, {
props: {
options: manyOptions,
scrollable: true,
dataTest,
},
slots: {
next: `<div class="${slotClass}">${slotContent}</div>`,
},
});
// Mock the scroll position to show right arrow
const scrollContainer = component.find(`[vl-key="tabs"]`).element;
Object.defineProperty(scrollContainer, "scrollLeft", { value: 0 });
Object.defineProperty(scrollContainer, "scrollWidth", { value: 1000 });
Object.defineProperty(scrollContainer, "clientWidth", { value: 500 });
// Trigger scroll event
await component.find("[vl-key='tabs']").trigger("scroll");
// Now the right arrow should be visible
expect(component.find(`.${slotClass}`).exists()).toBe(true);
expect(component.find(`.${slotClass}`).text()).toBe(slotContent);
});
});
// Events tests
describe("Events", () => {
// Update:modelValue event
it("emits update:modelValue event when tab is clicked", async () => {
const component = mount(UTabs, {
props: {
options,
modelValue: "tab1",
},
});
// Find the second tab and click it
const secondTab = component.findAllComponents(UTab)[1];
await secondTab.trigger("click");
// Check that the update:modelValue event was emitted with the correct value
expect(component.emitted("update:modelValue")).toBeTruthy();
expect(component.emitted("update:modelValue")?.[0]).toEqual(["tab2"]);
});
});
// Exposed refs tests
describe("Exposed refs", () => {
// wrapperRef
it("exposes wrapperRef", () => {
const singleOption = [options[0]];
const component = mount(UTabs, {
props: {
options: singleOption,
},
});
expect(component.vm.wrapperRef).toBeDefined();
});
});
});