Skip to content
This repository has been archived by the owner on Jul 2, 2024. It is now read-only.

DEVPROD-1977: Update tests table to use LeafyGreen #2213

Merged
merged 9 commits into from
Jan 18, 2024
50 changes: 27 additions & 23 deletions cypress/integration/task/test_table.ts
Original file line number Diff line number Diff line change
@@ -11,62 +11,65 @@ describe("Tests Table", () => {
.should("be.visible")
.should("not.have.attr", "data-loading", "true");
};

beforeEach(() => {
visitAndWait(TESTS_ROUTE);
});

it("Test count should update to reflect filtered values", () => {
cy.contains(TABLE_SORT_SELECTOR, "Name").click();
const nameSortControl = "button[aria-label='Sort by Name']";
cy.get(nameSortControl).click();

cy.dataCy("filtered-count").contains(20);
cy.dataCy("total-count").contains(20);

cy.toggleTableFilter(2);

cy.get(".cy-checkbox").contains("Fail").click({ force: true });
cy.dataCy("status-treeselect").click();
cy.getInputByLabel("Fail").check({ force: true });
cy.dataCy("filtered-count").contains(1);
cy.dataCy("total-count").contains(20);

cy.toggleTableFilter(1);
cy.dataCy("testname-input-wrapper")
.find("input")
.as("testnameInputWrapper")
.focus();
cy.get("@testnameInputWrapper").type("hello{enter}");
cy.dataCy("test-name-filter").click();
cy.dataCy("test-name-filter-input-filter").type("hello{enter}");

cy.dataCy("filtered-count").contains(0);
cy.dataCy("total-count").contains(20);
});

it("Adjusts query params when table headers are clicked", () => {
cy.contains(TABLE_SORT_SELECTOR, "Name").click();
const nameSortControl = "button[aria-label='Sort by Name']";
const statusSortControl = "button[aria-label='Sort by Status']";
const durationSortControl = "button[aria-label='Sort by Time']";

cy.get(nameSortControl).click();

cy.location().should((loc) => {
expect(loc.pathname).to.equal(TESTS_ROUTE);
expect(loc.search).to.include("sortBy=TEST_NAME");
expect(loc.search).to.include(ASCEND_PARAM);
});

cy.contains(TABLE_SORT_SELECTOR, "Status").click();
cy.get(statusSortControl).click();
cy.location().should((loc) => {
expect(loc.pathname).to.equal(TESTS_ROUTE);
expect(loc.search).to.include("sortBy=STATUS");
expect(loc.search).to.include(ASCEND_PARAM);
});

cy.contains(TABLE_SORT_SELECTOR, "Status").click();
cy.get(statusSortControl).click();
cy.location().should((loc) => {
expect(loc.pathname).to.equal(TESTS_ROUTE);
expect(loc.search).to.include("sortBy=STATUS");
expect(loc.search).to.include(DESCEND_PARAM);
});

cy.contains(TABLE_SORT_SELECTOR, "Time").click();
cy.get(durationSortControl).click();
cy.location().should((loc) => {
expect(loc.pathname).to.equal(TESTS_ROUTE);
expect(loc.search).to.include("sortBy=DURATION");
expect(loc.search).to.include(ASCEND_PARAM);
});

cy.contains(TABLE_SORT_SELECTOR, "Time").click();
cy.get(durationSortControl).click();
cy.location().should((loc) => {
expect(loc.pathname).to.equal(TESTS_ROUTE);
expect(loc.search).to.include("sortBy=DURATION");
@@ -82,10 +85,10 @@ describe("Tests Table", () => {
it("Clicking on 'All' checkbox adds all statuses to URL", () => {
clickingCheckboxUpdatesUrlAndRendersFetchedResults({
checkboxDisplayName: "All",
pathname: TESTS_ROUTE,
openFilter: () => cy.dataCy("status-treeselect").click(),
paramName: "statuses",
pathname: TESTS_ROUTE,
search: "all,pass,fail,skip,silentfail",
openFilter: () => cy.toggleTableFilter(2),
});
});

@@ -97,12 +100,14 @@ describe("Tests Table", () => {
];

it("Checking multiple statuses adds them all to the URL", () => {
cy.toggleTableFilter(2);
cy.dataCy("status-treeselect").click();
statuses.forEach(({ display }) => {
cy.get(".cy-checkbox").contains(display).click({ force: true });
cy.getInputByLabel(display).check({ force: true });
});
cy.location().should((loc) => {
expect(loc.search).to.include("statuses=pass,silentfail,fail,skip,all");
expect(decodeURIComponent(loc.search)).to.include(
`statuses=${statuses.map(({ key }) => key).join(",")}`
);
});
});
});
@@ -112,8 +117,8 @@ describe("Tests Table", () => {

it("Typing in test name filter updates testname query param", () => {
visitAndWait(TESTS_ROUTE);
cy.toggleTableFilter(1);
cy.dataCy("testname-input-wrapper")
cy.dataCy("test-name-filter").click();
cy.dataCy("test-name-filter-wrapper")
.find("input")
.as("testnameInputWrapper")
.focus();
@@ -179,7 +184,6 @@ describe("Tests Table", () => {
});
});

const TABLE_SORT_SELECTOR = ".ant-table-column-sorters";
const DESCEND_PARAM = "sortDir=DESC";
const ASCEND_PARAM = "sortDir=ASC";
const TESTS_ROUTE =
4 changes: 2 additions & 2 deletions cypress/utils/index.ts
Original file line number Diff line number Diff line change
@@ -22,9 +22,9 @@ export const urlSearchParamsAreUpdated = ({ paramName, pathname, search }) => {
cy.location().should((loc) => {
expect(loc.pathname).to.equal(pathname);
if (search === null) {
expect(loc.search).to.not.include(paramName);
expect(decodeURIComponent(loc.search)).to.not.include(paramName);
} else {
expect(loc.search).to.include(search);
expect(decodeURIComponent(loc.search)).to.include(search);
}
});
};
8 changes: 2 additions & 6 deletions src/analytics/task/useTaskAnalytics.ts
Original file line number Diff line number Diff line change
@@ -15,14 +15,10 @@ import { RequiredQueryParams, LogTypes } from "types/task";

type LogViewer = "raw" | "html" | "parsley" | "lobster";
type Action =
| { name: "Filter Tests"; filterBy: string }
| { name: "Filter Tests"; filterBy: string | string[] }
| {
name: "Sort Tests Table";
sortBy:
| TestSortCategory.TestName
| TestSortCategory.Status
| TestSortCategory.BaseStatus
| TestSortCategory.Duration;
sortBy: TestSortCategory | TestSortCategory[];
}
| {
name: "Sort Execution Tasks Table";
6 changes: 4 additions & 2 deletions src/components/Table/BaseTable.tsx
Original file line number Diff line number Diff line change
@@ -156,6 +156,8 @@ export const BaseTable = forwardRef(
}
);

const cellPaddingStyle = { paddingBottom: size.xxs, paddingTop: size.xxs };

const RenderableRow = <T extends LGRowData>({
row,
virtualRow,
@@ -174,7 +176,7 @@ const RenderableRow = <T extends LGRowData>({
virtualRow={virtualRow}
>
{row.getVisibleCells().map((cell) => (
<Cell key={cell.id} style={{ padding: `${size.xxs} 2px` }}>
<Cell key={cell.id} style={cellPaddingStyle}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</Cell>
))}
@@ -192,7 +194,7 @@ const RenderableRow = <T extends LGRowData>({
virtualRow={virtualRow}
>
{subRow.getVisibleCells().map((cell) => (
<Cell key={cell.id}>
<Cell key={cell.id} style={cellPaddingStyle}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</Cell>
))}
2 changes: 1 addition & 1 deletion src/constants/routes.ts
Original file line number Diff line number Diff line change
@@ -174,7 +174,7 @@ export const getAllHostsRoute = (options?: GetAllHostsRouteOptions) => {
return `${paths.hosts}?${queryParams}`;
};

interface GetTaskRouteOptions {
export interface GetTaskRouteOptions {
tab?: TaskTab;
execution?: number;
[key: string]: any;
4 changes: 2 additions & 2 deletions src/hooks/useTableSort.ts
Original file line number Diff line number Diff line change
@@ -4,7 +4,7 @@ import { SortDirection } from "gql/generated/types";
import { useQueryParams } from "hooks/useQueryParam";

interface Props {
sendAnalyticsEvents?: () => void;
sendAnalyticsEvents?: (sorter?: SortingState) => void;
}

type CallbackType = (sorter: SortingState) => void;
@@ -19,7 +19,7 @@ export const useTableSort = (props?: Props): CallbackType => {
const [queryParams, setQueryParams] = useQueryParams();

const tableChangeHandler = ((sorter: SortingState) => {
props?.sendAnalyticsEvents?.();
props?.sendAnalyticsEvents?.(sorter);

const nextQueryParams = {
...queryParams,
13 changes: 0 additions & 13 deletions src/pages/Task.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { useEffect } from "react";
import { useQuery } from "@apollo/client";
import styled from "@emotion/styled";
import { useParams, useLocation } from "react-router-dom";
@@ -68,18 +67,6 @@ export const Task = () => {
const attributed = annotation?.issues?.length > 0;
const isDisplayTask = executionTasksFull != null;

useEffect(() => {
if (
id === task?.id &&
Number.isNaN(selectedExecution) &&
latestExecution !== undefined
) {
updateQueryParams({
execution: `${latestExecution}`,
});
}
}, [id, selectedExecution, latestExecution, updateQueryParams, task?.id]);

if (error) {
return <PageDoesNotExist />;
}
38 changes: 26 additions & 12 deletions src/pages/task/TaskTabs.tsx
Original file line number Diff line number Diff line change
@@ -5,7 +5,7 @@ import { useTaskAnalytics } from "analytics";
import { TrendChartsPlugin } from "components/PerfPlugin";
import { StyledTabs } from "components/styles/StyledTabs";
import { TabLabelWithBadge } from "components/TabLabelWithBadge";
import { getTaskRoute } from "constants/routes";
import { getTaskRoute, GetTaskRouteOptions } from "constants/routes";
import { TaskQuery } from "gql/generated/types";
import { usePrevious } from "hooks";
import { useTabShortcut } from "hooks/useTabShortcut";
@@ -175,19 +175,33 @@ export const TaskTabs: React.FC<TaskTabProps> = ({ isDisplayTask, task }) => {
});

useEffect(() => {
const query = parseQueryString(location.search);
const newRoute = getTaskRoute(id, {
tab: activeTabs[selectedTab],
...query,
});
navigate(newRoute, { replace: true });
if (previousTab !== undefined && previousTab !== selectedTab) {
taskAnalytics.sendEvent({
name: "Change Tab",
if (previousTab !== selectedTab) {
const query = parseQueryString(location.search);
const params: GetTaskRouteOptions = {
tab: activeTabs[selectedTab],
});
...query,
};

// Introduce execution query parameter if none is set.
if (
id === task?.id &&
query.execution === undefined &&
task.latestExecution !== undefined
) {
params.execution = task.latestExecution;
}

const newRoute = getTaskRoute(id, params);
navigate(newRoute, { replace: true });

if (previousTab !== undefined) {
taskAnalytics.sendEvent({
name: "Change Tab",
tab: activeTabs[selectedTab],
});
}
}
}, [selectedTab, execution]); // eslint-disable-line react-hooks/exhaustive-deps
}, [selectedTab]); // eslint-disable-line react-hooks/exhaustive-deps

return (
<StyledTabs
Loading