-
Notifications
You must be signed in to change notification settings - Fork 23
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Issue #2029] Prepare for Nava fork to HHS
- Loading branch information
Showing
8 changed files
with
225 additions
and
41 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -54,4 +54,4 @@ npm-debug.log* | |
|
||
# pa11y | ||
screenshots-output/* | ||
pa11y_output.txt | ||
pa11y_output.txt |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import BetaAlert from "src/components/BetaAlert"; | ||
import { GridContainer } from "@trussworks/react-uswds"; | ||
import Link from "next/link"; | ||
import { useTranslations } from "next-intl"; | ||
import { getTranslations, unstable_setRequestLocale } from "next-intl/server"; | ||
import { Metadata } from "next"; | ||
|
||
export async function generateMetadata() { | ||
const t = await getTranslations({ locale: "en" }); | ||
const meta: Metadata = { | ||
title: t("ErrorPages.page_not_found.title"), | ||
description: t("Index.meta_description"), | ||
}; | ||
return meta; | ||
} | ||
|
||
export default function NotFound() { | ||
unstable_setRequestLocale("en"); | ||
const t = useTranslations("ErrorPages.page_not_found"); | ||
|
||
return ( | ||
<> | ||
<BetaAlert /> | ||
<GridContainer className="padding-y-1 tablet:padding-y-3 desktop-lg:padding-y-15"> | ||
<h1 className="nj-h1">{t("title")}</h1> | ||
<p className="margin-bottom-2">{t("message_content_1")}</p> | ||
<Link className="usa-button" href="/" key="returnToHome"> | ||
{t("visit_homepage_button")} | ||
</Link> | ||
</GridContainer> | ||
</> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import { Page, expect, test } from "@playwright/test"; | ||
import { | ||
expectURLContainsQueryParam, | ||
fillSearchInputAndSubmit, | ||
} from "./searchSpecUtil"; | ||
|
||
import { BrowserContextOptions } from "playwright-core"; | ||
|
||
interface PageProps { | ||
page: Page; | ||
browserName?: string; | ||
contextOptions?: BrowserContextOptions; | ||
} | ||
|
||
test.describe("Search page tests", () => { | ||
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", | ||
"Skipping test for WebKit due to a query param issue.", | ||
); | ||
|
||
const searchTerm = "0resultearch"; | ||
|
||
await fillSearchInputAndSubmit(searchTerm, page); | ||
await new Promise((resolve) => setTimeout(resolve, 3250)); | ||
expectURLContainsQueryParam(page, "query", searchTerm); | ||
|
||
// eslint-disable-next-line testing-library/prefer-screen-queries | ||
const resultsHeading = page.getByRole("heading", { | ||
name: /0 Opportunities/i, | ||
}); | ||
await expect(resultsHeading).toBeVisible(); | ||
|
||
await expect(page.locator("div.usa-prose h2")).toHaveText( | ||
"Your search did not return any results.", | ||
); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
// ========================= | ||
// Test Helper Functions | ||
// ========================= | ||
|
||
import { Locator, Page, expect } from "@playwright/test"; | ||
|
||
export function getSearchInput(page: Page) { | ||
return page.locator("#query"); | ||
} | ||
|
||
export async function fillSearchInputAndSubmit(term: string, page: Page) { | ||
const searchInput = getSearchInput(page); | ||
await searchInput.fill(term); | ||
await page.click(".usa-search >> button[type='submit']"); | ||
expectURLContainsQueryParam(page, "query", term); | ||
} | ||
|
||
export function expectURLContainsQueryParam( | ||
page: Page, | ||
queryParamName: string, | ||
queryParamValue: string, | ||
) { | ||
const currentURL = page.url(); | ||
expect(currentURL).toContain(`${queryParamName}=${queryParamValue}`); | ||
} | ||
|
||
export async function waitForURLContainsQueryParam( | ||
page: Page, | ||
queryParamName: string, | ||
queryParamValue: string, | ||
timeout = 30000, // query params get set after a debounce period | ||
) { | ||
const endTime = Date.now() + timeout; | ||
|
||
while (Date.now() < endTime) { | ||
const url = new URL(page.url()); | ||
const params = new URLSearchParams(url.search); | ||
const actualValue = params.get(queryParamName); | ||
|
||
if (actualValue === queryParamValue) { | ||
return; | ||
} | ||
|
||
await page.waitForTimeout(500); | ||
} | ||
|
||
throw new Error( | ||
`URL did not contain query parameter ${queryParamName}=${queryParamValue} within ${timeout}ms`, | ||
); | ||
} | ||
|
||
export async function clickSearchNavLink(page: Page) { | ||
await page.click("nav >> text=Search"); | ||
} | ||
|
||
export function getMobileMenuButton(page: Page) { | ||
return page.locator("button >> text=MENU"); | ||
} | ||
|
||
export async function hasMobileMenu(page: Page) { | ||
const menuButton = getMobileMenuButton(page); | ||
return await menuButton.isVisible(); | ||
} | ||
|
||
export async function clickMobileNavMenu(menuButton: Locator) { | ||
await menuButton.click(); | ||
} | ||
|
||
export async function expectCheckboxIDIsChecked( | ||
page: Page, | ||
idWithHash: string, | ||
) { | ||
const checkbox: Locator = page.locator(idWithHash); | ||
await expect(checkbox).toBeChecked(); | ||
} | ||
|
||
export async function toggleCheckboxes( | ||
page: Page, | ||
checkboxObject: Record<string, string>, | ||
queryParamName: string, | ||
) { | ||
let runningQueryParams = ""; | ||
for (const [checkboxID, queryParamValue] of Object.entries(checkboxObject)) { | ||
await toggleCheckbox(page, checkboxID); | ||
runningQueryParams += runningQueryParams | ||
? `,${queryParamValue}` | ||
: queryParamValue; | ||
await waitForURLContainsQueryParam( | ||
page, | ||
queryParamName, | ||
runningQueryParams, | ||
); | ||
} | ||
} | ||
|
||
export async function toggleCheckbox(page: Page, idWithoutHash: string) { | ||
const checkBox = page.locator(`label[for=${idWithoutHash}]`); | ||
await checkBox.isEnabled(); | ||
await checkBox.click(); | ||
} | ||
|
||
export async function refreshPageWithCurrentURL(page: Page) { | ||
const currentURL = page.url(); | ||
await page.goto(currentURL); // go to new url in same tab | ||
return page; | ||
} | ||
|
||
export async function selectSortBy(page: Page, sortByValue: string) { | ||
await page.locator("#search-sort-by-select").selectOption(sortByValue); | ||
} | ||
|
||
export async function expectSortBy(page: Page, value: string) { | ||
const selectedValue = await page | ||
.locator('select[name="search-sort-by"]') | ||
.inputValue(); | ||
expect(selectedValue).toBe(value); | ||
} | ||
|
||
export async function waitForSearchResultsLoaded(page: Page) { | ||
// Wait for number of opportunities to show | ||
const resultsHeading = page.locator('h2:has-text("Opportunities")'); | ||
await resultsHeading.waitFor({ state: "visible", timeout: 60000 }); | ||
} | ||
|
||
export async function clickAccordionWithTitle( | ||
page: Page, | ||
accordionTitle: string, | ||
) { | ||
await page | ||
.locator(`button.usa-accordion__button:has-text("${accordionTitle}")`) | ||
.click(); | ||
} |