From b01350ed88ddffa5032c80eb12987bde5e060d6b Mon Sep 17 00:00:00 2001 From: Ryan Lewis Date: Thu, 16 May 2024 15:36:31 -0700 Subject: [PATCH] add new e2e tests --- frontend/tests/e2e/search/search.spec.ts | 49 +++++++++++++++- frontend/tests/e2e/search/searchSpecUtil.ts | 62 ++++++++++++++++++++- 2 files changed, 106 insertions(+), 5 deletions(-) diff --git a/frontend/tests/e2e/search/search.spec.ts b/frontend/tests/e2e/search/search.spec.ts index e62743739..6d8cfd676 100644 --- a/frontend/tests/e2e/search/search.spec.ts +++ b/frontend/tests/e2e/search/search.spec.ts @@ -1,18 +1,23 @@ import { clickAccordionWithTitle, + clickLastPaginationPage, clickMobileNavMenu, + clickPaginationPageNumber, clickSearchNavLink, expectCheckboxIDIsChecked, expectSortBy, expectURLContainsQueryParam, fillSearchInputAndSubmit, + getFirstSearchResultTitle, + getLastSearchResultTitle, getMobileMenuButton, getSearchInput, hasMobileMenu, refreshPageWithCurrentURL, + selectOppositeSortOption, selectSortBy, toggleCheckboxes, - waitForSearchResultsLoaded, + waitForSearchResultsInitialLoad, } from "./searchSpecUtil"; import { expect, test } from "@playwright/test"; @@ -119,7 +124,7 @@ test.describe("Search page tests", () => { await selectSortBy(page, "agencyDesc"); - await waitForSearchResultsLoaded(page); + await waitForSearchResultsInitialLoad(page); await fillSearchInputAndSubmit(searchTerm, page); await toggleCheckboxes(page, statusCheckboxes, "status"); @@ -168,7 +173,45 @@ test.describe("Search page tests", () => { } }); - test('resets page back to 1 when choosing a filter', () => { + test("resets page back to 1 when choosing a filter", async ({ page }) => { + await clickPaginationPageNumber(page, 2); + // Verify that page 1 is highlighted + let currentPageButton = page.locator(".usa-pagination__button.usa-current"); + await expect(currentPageButton).toHaveAttribute("aria-label", "Page 2"); + + // Select the 'Closed' checkbox under 'Opportunity status' + const statusCheckboxes = { + "status-closed": "closed", + }; + await toggleCheckboxes(page, statusCheckboxes, "status"); + + // Wait for the page to reload + await waitForSearchResultsInitialLoad(page); + + // Verify that page 1 is highlighted + currentPageButton = page.locator(".usa-pagination__button.usa-current"); + await expect(currentPageButton).toHaveAttribute("aria-label", "Page 1"); + + // It should not have a page query param set + expectURLContainsQueryParam(page, "page", "1", false); + }); + + test("last result becomes first result when flipping sort order", async ({ + page, + }) => { + await clickLastPaginationPage(page); + + // Wait for the search results to load again + await waitForSearchResultsInitialLoad(page); + + // Note the last result on the last page + const lastSearchResultTitle = await getLastSearchResultTitle(page); + + await selectOppositeSortOption(page); + + const firstSearchResultTitle = await getFirstSearchResultTitle(page); + + expect(firstSearchResultTitle).toBe(lastSearchResultTitle); }); }); diff --git a/frontend/tests/e2e/search/searchSpecUtil.ts b/frontend/tests/e2e/search/searchSpecUtil.ts index 87d066533..8d7a7da40 100644 --- a/frontend/tests/e2e/search/searchSpecUtil.ts +++ b/frontend/tests/e2e/search/searchSpecUtil.ts @@ -19,9 +19,16 @@ export function expectURLContainsQueryParam( page: Page, queryParamName: string, queryParamValue: string, + shouldContain = true, ) { const currentURL = page.url(); - expect(currentURL).toContain(`${queryParamName}=${queryParamValue}`); + const queryParam = `${queryParamName}=${queryParamValue}`; + + if (shouldContain) { + expect(currentURL).toContain(queryParam); + } else { + expect(currentURL).not.toContain(queryParam); + } } export async function waitForURLContainsQueryParam( @@ -116,7 +123,7 @@ export async function expectSortBy(page: Page, value: string) { expect(selectedValue).toBe(value); } -export async function waitForSearchResultsLoaded(page: Page) { +export async function waitForSearchResultsInitialLoad(page: Page) { // Wait for number of opportunities to show const resultsHeading = page.locator('h2:has-text("Opportunities")'); await resultsHeading.waitFor({ state: "visible", timeout: 60000 }); @@ -130,3 +137,54 @@ export async function clickAccordionWithTitle( .locator(`button.usa-accordion__button:has-text("${accordionTitle}")`) .click(); } + +export async function clickPaginationPageNumber( + page: Page, + pageNumber: number, +) { + const paginationButton = page.locator( + `button[data-testid="pagination-page-number"][aria-label="Page ${pageNumber}"]`, + ); + await paginationButton.first().click(); +} + +export async function clickLastPaginationPage(page: Page) { + const paginationButtons = page.locator("li > button"); + const count = await paginationButtons.count(); + + // must be more than 1 page + if (count > 2) { + await paginationButtons.nth(count - 2).click(); + } +} + +export async function getFirstSearchResultTitle(page: Page) { + const firstResultSelector = page.locator( + ".usa-list--unstyled > li:first-child h2 a", + ); + return await firstResultSelector.textContent(); +} + +export async function getLastSearchResultTitle(page: Page) { + const lastResultSelector = page.locator( + ".usa-list--unstyled > li:last-child h2 a", + ); + return await lastResultSelector.textContent(); +} + +// If descending, select the ascending variant +export async function selectOppositeSortOption(page: Page) { + const sortByDropdown = page.locator("#search-sort-by-select"); + const currentValue = await sortByDropdown.inputValue(); + let oppositeValue; + + if (currentValue.includes("Asc")) { + oppositeValue = currentValue.replace("Asc", "Desc"); + } else if (currentValue.includes("Desc")) { + oppositeValue = currentValue.replace("Desc", "Asc"); + } else { + throw new Error(`Unexpected sort value: ${currentValue}`); + } + + await sortByDropdown.selectOption(oppositeValue); +}