vueless
Version:
Vue Styleless UI Component Library, powered by Tailwind CSS.
419 lines (345 loc) • 11.5 kB
text/typescript
import { mount } from "@vue/test-utils";
import { describe, it, expect } from "vitest";
import UPagination from "../UPagination.vue";
import UButton from "../../ui.button/UButton.vue";
import UIcon from "../../ui.image-icon/UIcon.vue";
import type { Props } from "../types";
describe("UPagination.vue", () => {
// Props tests
describe("Props", () => {
// Variant prop
it("applies the correct variant to buttons", async () => {
const variants = ["solid", "outlined", "subtle", "soft", "ghost"];
variants.forEach((variant) => {
const component = mount(UPagination, {
props: {
variant: variant as Props["variant"],
modelValue: 2,
total: 100,
perPage: 10,
},
});
const activeButton = component
.findAllComponents(UButton)
.find((button) => button.text() === "2");
expect(activeButton?.props("variant")).toBe(variant);
});
});
// Size prop
it("applies the correct size to buttons", async () => {
const sizes = {
sm: "text-small",
md: "text-medium",
lg: "text-large",
};
Object.entries(sizes).forEach(([size, classes]) => {
const component = mount(UPagination, {
props: {
size: size as Props["size"],
modelValue: 1,
total: 100,
perPage: 10,
},
});
const buttons = component.findAllComponents(UButton);
// Check that all buttons have the correct font-size class
buttons.forEach((button) => {
expect(button.attributes("class")).toContain(classes);
});
});
});
// ModelValue prop
it("correctly highlights the current page", () => {
const currentPage = 3;
const component = mount(UPagination, {
props: {
modelValue: currentPage,
total: 100,
perPage: 10,
},
});
const activeButton = component
.findAllComponents(UButton)
.find((button) => button.text() === String(currentPage));
expect(activeButton?.props("variant")).toBe("solid");
});
// Total and perPage props
it("calculates the correct number of pages", () => {
const total = 100;
const perPage = 10;
const expectedAmountOfButtons = 5;
const component = mount(UPagination, {
props: {
modelValue: 1,
total,
perPage,
},
});
// Find all page buttons (excluding navigation buttons)
const pageButtons = component.findAllComponents(UButton).filter((button) => {
const text = button.text();
return text && !isNaN(Number(text));
});
// With default limit of 5, we should see 5 page buttons or less
expect(pageButtons.length).toBeLessThanOrEqual(expectedAmountOfButtons);
});
// Limit prop
it("respects the limit of visible pages", () => {
const limit = 3;
const component = mount(UPagination, {
props: {
modelValue: 5,
total: 100,
perPage: 10,
limit,
},
});
// Find all page buttons (excluding navigation buttons)
const pageButtons = component.findAllComponents(UButton).filter((button) => {
const text = button.text();
return text && !isNaN(Number(text));
});
expect(pageButtons.length).toBeLessThanOrEqual(limit);
});
// FirstLabel, PrevLabel, NextLabel, LastLabel props
it("displays custom navigation labels", () => {
const firstLabel = "First";
const prevLabel = "Prev";
const nextLabel = "Next";
const lastLabel = "Last";
const component = mount(UPagination, {
props: {
modelValue: 5,
total: 100,
perPage: 10,
firstLabel,
prevLabel,
nextLabel,
lastLabel,
},
});
const buttons = component.findAllComponents(UButton);
expect(buttons[0].text()).toBe(firstLabel);
expect(buttons[1].text()).toBe(prevLabel);
expect(buttons[buttons.length - 2].text()).toBe(nextLabel);
expect(buttons[buttons.length - 1].text()).toBe(lastLabel);
});
// Disabled prop
it("disables all buttons when disabled prop is true", () => {
const disabled = true;
const component = mount(UPagination, {
props: {
modelValue: 5,
total: 100,
perPage: 10,
disabled,
},
});
const buttons = component.findAllComponents(UButton);
// Check that all page buttons are disabled
const pageButtons = buttons.filter((button) => {
const text = button.text();
return text && !isNaN(Number(text));
});
pageButtons.forEach((button) => {
expect(button.attributes("disabled")).toBeDefined();
});
});
// Ellipsis prop
it("shows ellipsis when ellipsis prop is true", () => {
const ellipsis = true;
const expectedEllipsis = "…";
const component = mount(UPagination, {
props: {
ellipsis,
modelValue: 5,
total: 100,
perPage: 10,
},
});
// Check for ellipsis character
expect(component.html()).toContain(expectedEllipsis);
});
// ShowFirst and ShowLast props
it("hides first/last buttons when showFirst/showLast props are false", () => {
const component = mount(UPagination, {
props: {
modelValue: 5,
total: 100,
perPage: 10,
showFirst: false,
showLast: false,
},
});
const buttons = component.findAllComponents(UButton);
const firstButton = buttons[0];
const lastButton = buttons[buttons.length - 1];
// The first button should now be "prev" and the last button should be "next"
expect(firstButton.findComponent(UIcon).props("name")).toContain("chevron_left");
expect(lastButton.findComponent(UIcon).props("name")).toContain("chevron_right");
});
// DataTest prop
it("applies the correct data-test attribute", () => {
const dataTest = "test-pagination";
const component = mount(UPagination, {
props: {
modelValue: 1,
total: 100,
perPage: 10,
dataTest,
},
});
// Check that the first button has the correct data-test attribute
const firstButton = component.findComponent(UButton);
expect(firstButton.attributes("data-test")).toBe(`${dataTest}-first`);
});
});
// Slots tests
describe("Slots", () => {
// First slot
it("renders content from first slot", () => {
const slotContent = "Custom First";
const slotClass = "first-content";
const component = mount(UPagination, {
props: {
modelValue: 1,
total: 100,
perPage: 10,
},
slots: {
first: `<span class="${slotClass}">${slotContent}</span>`,
},
});
expect(component.find(`.${slotClass}`).exists()).toBe(true);
expect(component.find(`.${slotClass}`).text()).toBe(slotContent);
});
// Prev slot
it("renders content from prev slot", () => {
const slotContent = "Custom Prev";
const slotClass = "prev-content";
const component = mount(UPagination, {
props: {
modelValue: 2,
total: 100,
perPage: 10,
},
slots: {
prev: `<span class="${slotClass}">${slotContent}</span>`,
},
});
expect(component.find(`.${slotClass}`).exists()).toBe(true);
expect(component.find(`.${slotClass}`).text()).toBe(slotContent);
});
// Ellipsis slot
it("renders content from ellipsis slot", () => {
const slotContent = "......";
const slotClass = "ellipsis-content";
const component = mount(UPagination, {
props: {
modelValue: 5,
total: 100,
perPage: 10,
ellipsis: true,
},
slots: {
ellipsis: `<span class="${slotClass}">${slotContent}</span>`,
},
});
expect(component.find(`.${slotClass}`).exists()).toBe(true);
expect(component.find(`.${slotClass}`).text()).toBe(slotContent);
});
// Next slot
it("renders content from next slot", () => {
const slotContent = "Custom Next";
const slotClass = "next-content";
const component = mount(UPagination, {
props: {
modelValue: 1,
total: 100,
perPage: 10,
},
slots: {
next: `<span class="${slotClass}">${slotContent}</span>`,
},
});
expect(component.find(`.${slotClass}`).exists()).toBe(true);
expect(component.find(`.${slotClass}`).text()).toBe(slotContent);
});
// Last slot
it("renders content from last slot", () => {
const slotContent = "Custom Last";
const slotClass = "last-content";
const component = mount(UPagination, {
props: {
modelValue: 1,
total: 100,
perPage: 10,
},
slots: {
last: `<span class="${slotClass}">${slotContent}</span>`,
},
});
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 page is changed", async () => {
const component = mount(UPagination, {
props: {
modelValue: 1,
total: 100,
perPage: 10,
},
});
// Find the second page button and click it
const pageButtons = component.findAllComponents(UButton).filter((button) => {
const text = button.text();
return text && !isNaN(Number(text));
});
// Second button
await pageButtons[1].trigger("click");
expect(component.emitted("update:modelValue")).toBeTruthy();
expect(component.emitted("update:modelValue")?.[0]).toEqual([2]); // Second button value
});
// Navigation button clicks
it("navigates to correct pages when navigation buttons are clicked", async () => {
const component = mount(UPagination, {
props: {
modelValue: 5,
total: 100,
perPage: 10,
},
});
const buttons = component.findAllComponents(UButton);
// Click first button
await buttons[0].trigger("click");
expect(component.emitted("update:modelValue")?.[0]).toEqual([1]);
// Click prev button
await buttons[1].trigger("click");
expect(component.emitted("update:modelValue")?.[1]).toEqual([4]);
// Click next button
await buttons[buttons.length - 2].trigger("click");
expect(component.emitted("update:modelValue")?.[2]).toEqual([6]);
// Click last button
await buttons[buttons.length - 1].trigger("click");
expect(component.emitted("update:modelValue")?.[3]).toEqual([10]);
});
});
// Exposed refs tests
describe("Exposed refs", () => {
// paginationRef
it("exposes paginationRef", () => {
const component = mount(UPagination, {
props: {
modelValue: 1,
total: 100,
perPage: 10,
},
});
expect(component.vm.paginationRef).toBeDefined();
});
});
});