carbon-components-svelte/tests/DataTable/DataTableSearch.test.ts
Eric Liu f09c2e2c31
fix(toolbar-search): re-filter rows if DataTable rows change (#2154)
Fixes #2143

Make `ToolbarSearch` filtering reactive to `DataTable` rows.

Previously, `ToolbarSearch` did not update when `DataTable` rows
changed. Now it subscribes to the context rows and re-runs
`filterRows` in `afterUpdate` to prevent infinite loops.
2025-04-19 13:33:07 -07:00

231 lines
7.6 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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("15 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("15 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("15 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("15 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("00 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("12 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/);
});
});
it("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("15 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("12 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("15 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();
});
});