diff --git a/tests/DataTable/DataTableSearch.test.svelte b/tests/DataTable/DataTableSearch.test.svelte new file mode 100644 index 00000000..f333b343 --- /dev/null +++ b/tests/DataTable/DataTableSearch.test.svelte @@ -0,0 +1,78 @@ + + + + + + + + + + + + + diff --git a/tests/DataTable/DataTableSearch.test.ts b/tests/DataTable/DataTableSearch.test.ts new file mode 100644 index 00000000..71758718 --- /dev/null +++ b/tests/DataTable/DataTableSearch.test.ts @@ -0,0 +1,232 @@ +import { render, screen } from "@testing-library/svelte"; +import { user } from "../setup-tests"; +import DataTableSearch from "./DataTableSearch.test.svelte"; + +describe("DataTableSearch", () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + // Remove first row since it's the header + const getTableRows = () => screen.getAllByRole("row").slice(1); + const getNextPageButton = () => + screen.getByRole("button", { name: "Next page" }); + const getPrevPageButton = () => + screen.getByRole("button", { name: "Previous page" }); + const allRowsRendered = () => { + const tableRows = getTableRows(); + expect(tableRows).toHaveLength(5); + tableRows.forEach((row) => { + expect(row).toHaveTextContent(/Round robin|DNS delegation/); + }); + + expect(screen.getByText("1–5 of 10 items")).toBeInTheDocument(); + expect(screen.getByText("of 2 pages")).toBeInTheDocument(); + expect(getNextPageButton()).toBeEnabled(); + expect(getPrevPageButton()).toBeDisabled(); + }; + + it("renders non-persistent search input", async () => { + render(DataTableSearch); + + const searchBar = screen.getByRole("search"); + expect(searchBar).not.toHaveClass( + "bx--toolbar-search-container-persistent", + ); + expect(searchBar).not.toHaveClass("bx--toolbar-search-container-active"); + + const searchInput = screen.getByRole("searchbox"); + expect(searchInput).toHaveValue(""); + expect(searchInput).not.toHaveFocus(); + allRowsRendered(); + + await user.type(searchInput, "dns"); + expect(searchInput).toHaveValue("dns"); + expect(searchInput).toHaveFocus(); + expect(searchBar).toHaveClass("bx--toolbar-search-container-active"); + expect(screen.getByText("1–5 of 5 items")).toBeInTheDocument(); + expect(screen.getByText("of 1 page")).toBeInTheDocument(); + expect(getNextPageButton()).toBeDisabled(); + expect(getPrevPageButton()).toBeDisabled(); + + let tableRows = getTableRows(); + expect(tableRows).toHaveLength(5); + tableRows.forEach((row) => { + expect(row).toHaveTextContent("DNS"); + }); + + await user.keyboard("{Tab}{Enter}"); + expect(searchInput).toHaveValue(""); + expect(searchInput).toHaveFocus(); + allRowsRendered(); + + await user.keyboard("{Tab}"); + expect(searchBar).not.toHaveClass("bx--toolbar-search-container-active"); + }); + + it("renders persistent search input", async () => { + render(DataTableSearch, { + props: { + persistent: true, + }, + }); + + const searchBar = screen.getByRole("search"); + expect(searchBar).toHaveClass("bx--toolbar-search-container-persistent"); + + const searchInput = screen.getByRole("searchbox"); + expect(searchInput).toHaveValue(""); + expect(searchInput).not.toHaveFocus(); + allRowsRendered(); + + await user.type(searchInput, "dns"); + expect(searchInput).toHaveValue("dns"); + expect(searchInput).toHaveFocus(); + expect(screen.getByText("1–5 of 5 items")).toBeInTheDocument(); + expect(screen.getByText("of 1 page")).toBeInTheDocument(); + expect(getNextPageButton()).toBeDisabled(); + expect(getPrevPageButton()).toBeDisabled(); + + let tableRows = getTableRows(); + expect(tableRows).toHaveLength(5); + tableRows.forEach((row) => { + expect(row).toHaveTextContent("DNS"); + }); + + await user.keyboard("{Tab}{Enter}"); + expect(searchInput).toHaveValue(""); + expect(searchInput).toHaveFocus(); + allRowsRendered(); + }); + + it("renders with initial search value in non-persistent search input", async () => { + render(DataTableSearch, { + props: { + value: "round", + }, + }); + + const searchInput = screen.getByRole("searchbox"); + expect(searchInput).toHaveValue("round"); + expect(searchInput).not.toHaveFocus(); + + // Search bar should be active. + const searchBar = screen.getByRole("search"); + expect(searchBar).toHaveClass("bx--toolbar-search-container-active"); + + expect(screen.getByText("1–5 of 5 items")).toBeInTheDocument(); + expect(screen.getByText("of 1 page")).toBeInTheDocument(); + expect(getNextPageButton()).toBeDisabled(); + expect(getPrevPageButton()).toBeDisabled(); + + let tableRows = getTableRows(); + expect(tableRows).toHaveLength(5); + tableRows.forEach((row) => { + expect(row).toHaveTextContent("Round"); + }); + + await user.click( + screen.getByRole("button", { name: "Clear search input" }), + ); + expect(searchInput).toHaveValue(""); + expect(searchInput).toHaveFocus(); + allRowsRendered(); + + await user.type(searchInput, "rr"); + + tableRows = getTableRows(); + expect(tableRows).toHaveLength(0); + + expect(screen.getByText("0–0 of 0 items")).toBeInTheDocument(); + expect(screen.getByText("of 1 page")).toBeInTheDocument(); + expect(getNextPageButton()).toBeDisabled(); + expect(getPrevPageButton()).toBeDisabled(); + + await user.keyboard("{Escape}"); + expect(searchInput).toHaveValue(""); + expect(searchInput).toHaveFocus(); + allRowsRendered(); + + await user.keyboard("{Tab}"); + expect(searchBar).not.toHaveClass("bx--toolbar-search-container-active"); + }); + + it("can filter with a custom filter function", async () => { + render(DataTableSearch, { + props: { + shouldFilterRows: (row, value) => { + return ( + /(6|8)$/.test(row.name) && + row.rule.toLowerCase().includes((value + "").toLowerCase()) + ); + }, + }, + }); + + allRowsRendered(); + + const searchInput = screen.getByRole("searchbox"); + await user.type(searchInput, "round"); + expect(searchInput).toHaveValue("round"); + expect(searchInput).toHaveFocus(); + expect(screen.getByText("1–2 of 2 items")).toBeInTheDocument(); + expect(screen.getByText("of 1 page")).toBeInTheDocument(); + expect(getNextPageButton()).toBeDisabled(); + expect(getPrevPageButton()).toBeDisabled(); + + let tableRows = getTableRows(); + expect(tableRows).toHaveLength(2); + tableRows.forEach((row) => { + expect(row).toHaveTextContent("Round"); + expect(row).toHaveTextContent(/Load Balancer 6|Load Balancer 8/); + }); + }); + + // TODO: fix reactivity + it.skip("re-filters rows when toggled", async () => { + render(DataTableSearch); + + allRowsRendered(); + + const searchInput = screen.getByRole("searchbox"); + await user.type(searchInput, "round"); + expect(searchInput).toHaveValue("round"); + expect(searchInput).toHaveFocus(); + expect(screen.getByText("1–5 of 5 items")).toBeInTheDocument(); + expect(screen.getByText("of 1 page")).toBeInTheDocument(); + expect(getNextPageButton()).toBeDisabled(); + expect(getPrevPageButton()).toBeDisabled(); + + const toggleButton = screen.getByRole("button", { name: "Toggle rows" }); + await user.click(toggleButton); + + expect(searchInput).toHaveValue("round"); + expect(searchInput).not.toHaveFocus(); + + expect(screen.getByText("1–2 of 2 items")).toBeInTheDocument(); + expect(screen.getByText("of 1 page")).toBeInTheDocument(); + expect(getNextPageButton()).toBeDisabled(); + expect(getPrevPageButton()).toBeDisabled(); + + let tableRows = getTableRows(); + expect(tableRows).toHaveLength(2); + tableRows.forEach((row) => { + expect(row).toHaveTextContent("Round!"); + }); + + await user.click(toggleButton); + expect(searchInput).toHaveValue("round"); + expect(searchInput).not.toHaveFocus(); + expect(screen.getByText("1–5 of 5 items")).toBeInTheDocument(); + expect(screen.getByText("of 1 page")).toBeInTheDocument(); + expect(getNextPageButton()).toBeDisabled(); + expect(getPrevPageButton()).toBeDisabled(); + + await user.click( + screen.getByRole("button", { name: "Clear search input" }), + ); + expect(searchInput).toHaveValue(""); + expect(searchInput).toHaveFocus(); + allRowsRendered(); + }); +});