/* Copyright 2026 Marimo. All rights reserved. */ import { getCoreRowModel, useReactTable } from "@tanstack/react-table"; import { fireEvent, render, screen } from "@testing-library/react"; import { expect, test } from "vitest"; import { TooltipProvider } from "@/components/ui/tooltip"; import { DataTablePagination, matchingPageRanges } from "../pagination"; function PaginationHarness({ totalPages = 3, loading = false, }: { totalPages?: number; loading?: boolean; }) { const table = useReactTable({ locale: "en-US", data: [], columns: [], getCoreRowModel: getCoreRowModel(), manualPagination: true, pageCount: totalPages, }); return ( ); } test("named navigation controls preserve page updates and boundaries", () => { render(); expect(screen.getByRole("button", { name: "First page" })).toBeDisabled(); expect(screen.getByRole("button", { name: "Previous page" })).toBeDisabled(); fireEvent.click(screen.getByRole("button", { name: "Next page" })); expect( screen.getByRole("button", { name: "Choose page, current page 2 of 3" }), ).toBeEnabled(); fireEvent.click(screen.getByRole("button", { name: "Last page" })); expect(screen.getByRole("button", { name: "Next page" })).toBeDisabled(); expect(screen.getByRole("button", { name: "Last page" })).toBeDisabled(); fireEvent.click(screen.getByRole("button", { name: "Previous page" })); fireEvent.click(screen.getByRole("button", { name: "First page" })); expect( screen.getByRole("button", { name: "Choose page, current page 1 of 3" }), ).toBeEnabled(); expect(screen.getByRole("button", { name: "First page" })).toBeDisabled(); expect(screen.getByRole("button", { name: "Previous page" })).toBeDisabled(); expect(screen.getByRole("button", { name: "Next page" })).toBeEnabled(); expect(screen.getByRole("button", { name: "Last page" })).toBeEnabled(); }); test("loading prevents navigation and a single page disables controls", () => { const { rerender } = render(); fireEvent.click(screen.getByRole("button", { name: "Next page" })); fireEvent.click(screen.getByRole("button", { name: "Last page" })); expect( screen.getByRole("button", { name: "Choose page, current page 1 of 3" }), ).toBeEnabled(); rerender(); fireEvent.click(screen.getByRole("button", { name: "Next page" })); expect( screen.getByRole("button", { name: "Choose page, current page 2 of 3" }), ).toBeEnabled(); rerender(); for (const name of [ "First page", "Previous page", "Next page", "Last page", "Choose page, current page 1 of 1", ]) { expect(screen.getByRole("button", { name })).toBeDisabled(); } }); test("page picker exposes named dialog and search", () => { render(); fireEvent.click( screen.getByRole("button", { name: "Choose page, current page 1 of 3" }), ); expect( screen.getByRole("dialog", { name: "Choose page" }), ).toBeInTheDocument(); expect( screen.getByRole("combobox", { name: "Search pages" }), ).toBeInTheDocument(); }); test("empty prefix returns no ranges", () => { expect(matchingPageRanges("", 500)).toEqual([]); }); test("zero prefix returns no ranges", () => { expect(matchingPageRanges("0", 500)).toEqual([]); }); test("leading-zero prefix returns no ranges", () => { expect(matchingPageRanges("01", 500)).toEqual([]); }); test("single digit prefix", () => { expect(matchingPageRanges("5", 500)).toEqual([ [5, 5], [50, 59], [500, 500], ]); }); test("single digit prefix with exact totalPages boundary", () => { expect(matchingPageRanges("5", 55)).toEqual([ [5, 5], [50, 55], ]); }); test("multi-digit prefix", () => { expect(matchingPageRanges("12", 5000)).toEqual([ [12, 12], [120, 129], [1200, 1299], ]); }); test("prefix larger than totalPages returns no ranges", () => { expect(matchingPageRanges("999", 100)).toEqual([]); }); test("prefix equal to totalPages", () => { expect(matchingPageRanges("100", 100)).toEqual([[100, 100]]); }); test("prefix 1 with small totalPages", () => { expect(matchingPageRanges("1", 10)).toEqual([ [1, 1], [10, 10], ]); }); test("prefix 1 with totalPages=1", () => { expect(matchingPageRanges("1", 1)).toEqual([[1, 1]]); });