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

Commit

Permalink
[Issue #51]: debounce pagination (#53)
Browse files Browse the repository at this point in the history
## Summary
Fixes #51 

## Changes proposed
- Add 300ms debounce on pagination
  • Loading branch information
rylew1 authored Jun 3, 2024
1 parent 0f38c92 commit 9574e29
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 13 deletions.
14 changes: 11 additions & 3 deletions frontend/src/components/search/SearchPagination.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"use client";

import { Pagination } from "@trussworks/react-uswds";
import { useDebouncedCallback } from "use-debounce";
import { useFormStatus } from "react-dom";

export enum PaginationPosition {
Expand All @@ -19,6 +20,7 @@ interface SearchPaginationProps {
}

const MAX_SLOTS = 7;
const DEBOUNCE_TIME = 300;

export default function SearchPagination({
showHiddenInput,
Expand All @@ -31,6 +33,10 @@ export default function SearchPagination({
}: SearchPaginationProps) {
const { pending } = useFormStatus();

const debouncedHandlePageChange = useDebouncedCallback((newPage: number) => {
handlePageChange(newPage);
}, DEBOUNCE_TIME);

// If there's no results, don't show pagination
if (searchResultsLength < 1) {
return null;
Expand Down Expand Up @@ -59,9 +65,11 @@ export default function SearchPagination({
totalPages={totalPages}
currentPage={page}
maxSlots={MAX_SLOTS}
onClickNext={() => handlePageChange(page + 1)}
onClickPrevious={() => handlePageChange(page - 1)}
onClickPageNumber={(event, page) => handlePageChange(page)}
onClickNext={() => debouncedHandlePageChange(page + 1)}
onClickPrevious={() => debouncedHandlePageChange(page - 1)}
onClickPageNumber={(event: React.MouseEvent, page: number) =>
debouncedHandlePageChange(page)
}
/>
</>
);
Expand Down
40 changes: 30 additions & 10 deletions frontend/tests/e2e/search/search.spec.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Page, expect, test } from "@playwright/test";
import {
clickAccordionWithTitle,
clickLastPaginationPage,
Expand All @@ -20,9 +21,18 @@ import {
toggleCheckboxes,
waitForSearchResultsInitialLoad,
} from "./searchSpecUtil";
import { expect, test } from "@playwright/test";

test("should navigate from index to search page", async ({ page }) => {
import { BrowserContextOptions } from "playwright-core";

interface PageProps {
page: Page;
browserName?: string;
contextOptions?: BrowserContextOptions;
}

test("should navigate from index to search page", async ({
page,
}: PageProps) => {
// Start from the index page with feature flag set
await page.goto("/?_ff=showSearchV0:true");

Expand All @@ -48,15 +58,15 @@ test("should navigate from index to search page", async ({ page }) => {
});

test.describe("Search page tests", () => {
test.beforeEach(async ({ page }) => {
test.beforeEach(async ({ page }: PageProps) => {
// Navigate to the search page with the feature flag set
await page.goto("/search?_ff=showSearchV0:true");
});

test("should return 0 results when searching for obscure term", async ({
page,
browserName,
}) => {
}: PageProps) => {
// TODO (Issue #2005): fix test for webkit
test.skip(
browserName === "webkit",
Expand All @@ -80,7 +90,10 @@ test.describe("Search page tests", () => {
);
});

test("should show and hide loading state", async ({ page, browserName }) => {
test("should show and hide loading state", async ({
page,
browserName,
}: PageProps) => {
// TODO (Issue #2005): fix test for webkit
test.skip(
browserName === "webkit",
Expand All @@ -98,7 +111,10 @@ test.describe("Search page tests", () => {
await expect(loadingIndicator).toBeVisible();
await expect(loadingIndicator).toBeHidden();
});
test("should refresh and retain filters in a new tab", async ({ page }) => {

test("should refresh and retain filters in a new tab", async ({
page,
}: PageProps) => {
// Set all inputs, then refresh the page. Those same inputs should be
// set from query params.
const searchTerm = "education";
Expand Down Expand Up @@ -175,11 +191,15 @@ test.describe("Search page tests", () => {
}
});

test("resets page back to 1 when choosing a filter", async ({ page }) => {
test("resets page back to 1 when choosing a filter", async ({
page,
}: PageProps) => {
await clickPaginationPageNumber(page, 2);

// Verify that page 1 is highlighted
let currentPageButton = page.locator(".usa-pagination__button.usa-current");
let currentPageButton = page
.locator(".usa-pagination__button.usa-current")
.first();
await expect(currentPageButton).toHaveAttribute("aria-label", "Page 2");

// Select the 'Closed' checkbox under 'Opportunity status'
Expand All @@ -201,7 +221,7 @@ test.describe("Search page tests", () => {

test("last result becomes first result when flipping sort order", async ({
page,
}) => {
}: PageProps) => {
await selectSortBy(page, "opportunityTitleDesc");

await clickLastPaginationPage(page);
Expand All @@ -219,7 +239,7 @@ test.describe("Search page tests", () => {

test("number of results is the same with none or all opportunity status checked", async ({
page,
}) => {
}: PageProps) => {
const initialNumberOfOpportunityResults =
await getNumberOfOpportunitySearchResults(page);

Expand Down
5 changes: 5 additions & 0 deletions frontend/tests/e2e/search/searchSpecUtil.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,9 @@ export async function clickPaginationPageNumber(
`button[data-testid="pagination-page-number"][aria-label="Page ${pageNumber}"]`,
);
await paginationButton.first().click();

// Delay for pagination debounce
await page.waitForTimeout(400);
}

export async function clickLastPaginationPage(page: Page) {
Expand All @@ -156,6 +159,8 @@ export async function clickLastPaginationPage(page: Page) {
if (count > 2) {
await paginationButtons.nth(count - 2).click();
}
// Delay for pagination debounce
await page.waitForTimeout(400);
}

export async function getFirstSearchResultTitle(page: Page) {
Expand Down

0 comments on commit 9574e29

Please sign in to comment.