Files
voiceon-character-admin/src/shared/ui/__tests__/resource-pagination.test.tsx

74 lines
3.1 KiB
TypeScript

import { fireEvent, render, screen, within } from "@testing-library/react";
import { expect, test, vi } from "vitest";
import type { PageData } from "@/shared/api/pagination";
import { ResourcePagination } from "@/shared/ui/resource-pagination";
const pageData: PageData<string> = {
totalCount: 42,
page: 1,
size: 20,
hasNext: true,
items: [],
};
test("ResourcePagination uses PageData and real buttons for accessible page movement", () => {
const onPageChange = vi.fn();
const onSizeChange = vi.fn();
render(<ResourcePagination data={pageData} onPageChange={onPageChange} onSizeChange={onSizeChange} />);
const previous = screen.getByRole("button", { name: "이전 페이지" });
const next = screen.getByRole("button", { name: "다음 페이지" });
expect(previous.tagName).toBe("BUTTON");
expect(next).toBeEnabled();
expect(screen.getByText("총 42개 · 2페이지")).toBeInTheDocument();
fireEvent.click(previous);
fireEvent.click(next);
fireEvent.change(screen.getByLabelText("페이지 크기"), { target: { value: "50" } });
expect(onPageChange).toHaveBeenNthCalledWith(1, 0);
expect(onPageChange).toHaveBeenNthCalledWith(2, 2);
expect(onSizeChange).toHaveBeenCalledWith(50);
});
test("ResourcePagination disables unavailable previous and next actions", () => {
render(<ResourcePagination data={{ ...pageData, page: 0, hasNext: false }} onPageChange={vi.fn()} onSizeChange={vi.fn()} />);
expect(screen.getByRole("button", { name: "이전 페이지" })).toBeDisabled();
expect(screen.getByRole("button", { name: "다음 페이지" })).toBeDisabled();
});
test("ResourcePagination connects each page size label to a unique select", () => {
const { container } = render(
<>
<ResourcePagination data={pageData} onPageChange={vi.fn()} onSizeChange={vi.fn()} />
<ResourcePagination data={{ ...pageData, page: 0 }} onPageChange={vi.fn()} onSizeChange={vi.fn()} />
</>,
);
const selects = screen.getAllByLabelText("페이지 크기");
const selectIds = selects.map((select) => select.id);
const labels = Array.from(container.querySelectorAll("label"));
expect(new Set(selectIds).size).toBe(selectIds.length);
expect(labels.map((label) => label.control)).toEqual(selects);
});
test("ResourcePagination separates page size from stacked mobile movement controls", () => {
render(<ResourcePagination data={pageData} onPageChange={vi.fn()} onSizeChange={vi.fn()} />);
const sizeControls = screen.getByRole("group", { name: "페이지 크기 설정" });
const movementControls = screen.getByRole("group", { name: "페이지 이동" });
const previous = within(movementControls).getByRole("button", { name: "이전 페이지" });
const next = within(movementControls).getByRole("button", { name: "다음 페이지" });
expect(within(sizeControls).getByLabelText("페이지 크기")).toBeInTheDocument();
expect(sizeControls).not.toContainElement(previous);
expect(movementControls).toHaveClass("grid-cols-1");
expect(previous).toHaveClass("min-h-11", "w-full", "whitespace-nowrap");
expect(next).toHaveClass("min-h-11", "w-full", "whitespace-nowrap");
});