From 070a744a0ae504eb6bd6a22b2643155362d9fad3 Mon Sep 17 00:00:00 2001 From: Jordan Koschei Date: Wed, 9 Oct 2024 21:15:25 -0400 Subject: [PATCH 01/12] test: flesh out DataView tests --- .../src/Pagination/Pagination.tsx | 2 +- .../src/labs/DataFilters.tsx | 2 + .../src/labs/DataView/CardLayoutContent.tsx | 4 +- .../src/labs/DataView/DataView.test.tsx | 1135 +++++++++++++++-- .../src/labs/DataView/DataView.tsx | 3 +- .../properties/odyssey-react-mui.properties | 1 + 6 files changed, 1057 insertions(+), 90 deletions(-) diff --git a/packages/odyssey-react-mui/src/Pagination/Pagination.tsx b/packages/odyssey-react-mui/src/Pagination/Pagination.tsx index 3ca3b09e32..091531da86 100644 --- a/packages/odyssey-react-mui/src/Pagination/Pagination.tsx +++ b/packages/odyssey-react-mui/src/Pagination/Pagination.tsx @@ -286,7 +286,7 @@ const Pagination = ({ ); return variant === "paged" ? ( - + diff --git a/packages/odyssey-react-mui/src/labs/DataFilters.tsx b/packages/odyssey-react-mui/src/labs/DataFilters.tsx index 62e81d1647..e48a612dfe 100644 --- a/packages/odyssey-react-mui/src/labs/DataFilters.tsx +++ b/packages/odyssey-react-mui/src/labs/DataFilters.tsx @@ -630,6 +630,7 @@ const DataFilters = ({ variant="primary" endIcon={} type="submit" + ariaLabel={t("filters.submit.label")} /> )} @@ -697,6 +698,7 @@ const DataFilters = ({ variant="primary" endIcon={} type="submit" + ariaLabel={t("filters.submit.label")} /> )} diff --git a/packages/odyssey-react-mui/src/labs/DataView/CardLayoutContent.tsx b/packages/odyssey-react-mui/src/labs/DataView/CardLayoutContent.tsx index 2e19cbc400..19ad334242 100644 --- a/packages/odyssey-react-mui/src/labs/DataView/CardLayoutContent.tsx +++ b/packages/odyssey-react-mui/src/labs/DataView/CardLayoutContent.tsx @@ -92,7 +92,8 @@ const StackContainer = styled("div", { shouldForwardProp: (prop) => prop !== "odysseyDesignTokens" && prop !== "currentLayout" && - prop !== "maxGridColumns", + prop !== "maxGridColumns" && + prop !== "data-testid", })<{ odysseyDesignTokens: DesignTokens; currentLayout: CardLayout; @@ -175,6 +176,7 @@ const CardLayoutContent = ({ odysseyDesignTokens={odysseyDesignTokens} currentLayout={currentLayout} maxGridColumns={cardLayoutOptions.maxGridColumns ?? 3} + data-testId={currentLayout} > {isLoading ? ( diff --git a/packages/odyssey-react-mui/src/labs/DataView/DataView.test.tsx b/packages/odyssey-react-mui/src/labs/DataView/DataView.test.tsx index d3e834dcf1..e6c007d39a 100644 --- a/packages/odyssey-react-mui/src/labs/DataView/DataView.test.tsx +++ b/packages/odyssey-react-mui/src/labs/DataView/DataView.test.tsx @@ -11,148 +11,1109 @@ */ import { + findAllByRole, fireEvent, + getByText, + queryAllByRole, + queryByText, render, screen, waitFor, within, } from "@testing-library/react"; -import { DataView } from "./index"; +import { DataOnReorderRowsType, DataRow, DataView } from "./index"; import { data, columns, + Person, } from "@okta/odyssey-storybook/src/components/odyssey-labs/DataView/personData"; -import { filterData } from "@okta/odyssey-storybook/src/components/odyssey-labs/DataView/dataFunctions"; +import { + filterData, + reorderData, +} from "@okta/odyssey-storybook/src/components/odyssey-labs/DataView/dataFunctions"; +import { EmptyState } from "../../EmptyState"; +import { DataTableRowData } from "../../DataTable"; +import { MenuItem } from "../../MenuItem"; +import { Button } from "../../Button"; +import { MRT_RowSelectionState } from "material-react-table"; + +const simpleData: Person[] = [ + { + order: 1, + id: "1", + name: "Luke Skywalker", + city: "Mos Eisley", + state: "Tatooine", + age: 19, + risk: "low", + }, + { + order: 2, + id: "2", + name: "Han Solo", + city: "Corellia", + state: "Corellia", + age: 40, + risk: "medium", + }, + { + order: 3, + id: "3", + name: "Leia Organa", + city: "Alderaan City", + state: "Alderaan", + age: 19, + risk: "low", + }, + { + order: 4, + id: "4", + name: "Chewbacca", + city: "Kashyyyk City", + state: "Kashyyyk", + age: 50, + risk: "high", + }, + { + order: 5, + id: "5", + name: "C-3P0", + city: "Mos Espa", + state: "Tatooine", + age: 25, + risk: "low", + }, + { + order: 6, + id: "6", + name: "R2-D2", + city: "Theed", + state: "Naboo", + age: 25, + risk: "low", + }, +]; const getData = ({ ...props }) => { return filterData({ data, ...props }); }; +const getSimpleData = ({ ...props }) => { + return filterData({ data: [...simpleData], ...props }); +}; + +const itemProps = (row: DataRow) => ({ + title: row.name, +}); + describe("DataView", () => { - it("displays the expected number of rows by default", async () => { + it("displays a table view", async () => { render( - , +
+ +
, ); - const tableElement = await screen.findByRole("table", { name: "" }); - const rowElements = within(tableElement).getAllByRole("row", { - hidden: false, + waitFor(() => { + screen.findByTestId("container"); }); - expect(rowElements.length).toBe(21); + + expect(screen.queryByRole("table")).not.toBeNull(); + expect(screen.queryByTestId("list")).toBeNull(); + expect(screen.queryByTestId("grid")).toBeNull(); }); - it("displays the expected number of rows on load more", async () => { + it("displays a list view", async () => { + render( +
+ +
, + ); + + waitFor(() => { + screen.findByTestId("container"); + }); + + expect(screen.queryByRole("table")).toBeNull(); + expect(screen.queryByTestId("list")).not.toBeNull(); + expect(screen.queryByTestId("grid")).toBeNull(); + }); + + it("displays a grid view", async () => { + render( +
+ +
, + ); + + waitFor(() => { + screen.findByTestId("container"); + }); + + expect(screen.queryByRole("table")).toBeNull(); + expect(screen.queryByTestId("list")).toBeNull(); + expect(screen.queryByTestId("grid")).not.toBeNull(); + }); + + it("displays the layout switcher", async () => { + render( +
+ +
, + ); + + waitFor(() => { + screen.findByTestId("container"); + }); + + expect( + screen.queryByLabelText("Layout", { selector: "button" }), + ).not.toBeNull(); + }); + + it("can display meta text", async () => { + const metaText = "Last updated 12 hours ago"; + render( - , +
+ +
, ); - const tableElement = await screen.findByRole("table", { name: "" }); - const rowElements = within(tableElement).getAllByRole("row", { - hidden: false, + waitFor(() => { + screen.findByTestId("container"); }); - expect(rowElements.length).toBe(21); + + expect(screen.queryAllByText(metaText).length).toBe(1); + }); + + it("can filter rows", async () => { + render( +
+ +
, + ); waitFor(() => { - fireEvent.click(screen.getByText("Show more")); + screen.findByTestId("container"); + }); - const loadedRows = within(tableElement).getAllByRole("row", { - hidden: false, - }); - expect(loadedRows.length).toBe(41); + expect((await screen.findAllByText("Han Solo")).length).toBe(1); + expect((await screen.findAllByText("Luke Skywalker")).length).toBe(1); + + fireEvent.click(screen.getByLabelText("Filters", { selector: "button" })); + + const nameParagraph = screen.getByText(/Name/i, { selector: "p" }); + const nameMenuItem = nameParagraph.closest('[role="menuitem"]'); + if (nameMenuItem) { + fireEvent.click(nameMenuItem); + } + + const nameInput = screen.getByLabelText(/Name/i); + const submitButton = screen.getByLabelText("Submit", { + selector: "button", }); + fireEvent.change(nameInput, { target: { value: "Han Solo" } }); + fireEvent.click(submitButton); + + const updatedTable = await screen.findByRole("table"); + + expect(queryByText(updatedTable, "Han Solo")).not.toBeNull(); + expect(queryByText(updatedTable, "Luke Skywalker")).toBeNull(); }); - it("resets the rows when searching", async () => { + it("can search rows", async () => { render( - , +
+ +
, ); - const tableElement = await screen.findByRole("table", { name: "" }); - const rowElements = within(tableElement).getAllByRole("row", { - hidden: false, + waitFor(() => { + screen.findByTestId("container"); }); - expect(rowElements.length).toBe(21); - fireEvent.click(screen.getByText("Show more")); + expect((await screen.findAllByText("Han Solo")).length).toBe(1); + expect((await screen.findAllByText("Luke Skywalker")).length).toBe(1); + + const searchInput = screen.getByPlaceholderText(/Search/i); + const submitButton = screen.getByText("Search", { selector: "button" }); + fireEvent.change(searchInput, { target: { value: "Han Solo" } }); + fireEvent.click(submitButton); + + const updatedTable = await screen.findByRole("table"); + + expect(queryByText(updatedTable, "Han Solo")).not.toBeNull(); + expect(queryByText(updatedTable, "Luke Skywalker")).toBeNull(); + }); + it("can clear the search input", async () => { + render( +
+ +
, + ); + + waitFor(() => { + screen.findByTestId("container"); + }); + + expect((await screen.findAllByText("Han Solo")).length).toBe(1); + expect((await screen.findAllByText("Luke Skywalker")).length).toBe(1); + + const searchInput = screen.getByPlaceholderText(/Search/i); + const submitButton = screen.getByText("Search", { selector: "button" }); + fireEvent.change(searchInput, { target: { value: "Han Solo" } }); + fireEvent.click(submitButton); + + const updatedTable = await screen.findByRole("table"); + + expect(queryByText(updatedTable, "Han Solo")).not.toBeNull(); + expect(queryByText(updatedTable, "Luke Skywalker")).toBeNull(); + + expect(queryAllByRole(updatedTable, "row").length).toBe(2); + + const clearButton = screen.getByLabelText("Clear", { selector: "button" }); + fireEvent.click(clearButton); + + const clearedSearchTable = await screen.findByRole("table"); + + expect(searchInput).toHaveValue(""); + expect(queryAllByRole(clearedSearchTable, "row").length).toBe(7); + expect((await screen.findAllByText("Han Solo")).length).toBe(1); + expect((await screen.findAllByText("Luke Skywalker")).length).toBe(1); + }); + + it("can display row action menu", async () => { + const rowActionMenuItems = (row: DataTableRowData) => ( + Action for {row.original.name} + ); + + render( +
+ +
, + ); waitFor(() => { - const loadedRows = within(tableElement).getAllByRole("row", { - hidden: false, - }); - expect(loadedRows.length).toBe(41); + screen.findByTestId("container"); }); - const searchField = screen.getByPlaceholderText("Search"); - fireEvent.change(searchField, { target: { value: "John" } }); + expect((await screen.findAllByText("Luke Skywalker")).length).toBe(1); + expect(screen.queryByText("Action for Luke Skywalker")).toBeNull(); + + const rows = await screen.findAllByRole("row"); + const firstRow = rows[1]; + + const actionButton = within(firstRow).getByRole("button"); + fireEvent.click(actionButton); + + const actionMenu = await screen.findByRole("menuitem"); + expect(actionMenu.textContent).toBe("Action for Luke Skywalker"); + }); + it("can display row action buttons", async () => { + const rowActionButtons = (row: DataTableRowData) => ( +