mirror of
https://github.com/carbon-design-system/carbon-components-svelte.git
synced 2025-09-14 18:01:06 +00:00
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.
231 lines
7.6 KiB
TypeScript
231 lines
7.6 KiB
TypeScript
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/);
|
||
});
|
||
});
|
||
|
||
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("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();
|
||
});
|
||
});
|