diff --git a/frontend/src/app/[locale]/subscribe/confirmation/page.tsx b/frontend/src/app/[locale]/subscribe/confirmation/page.tsx
index 1b6c7b779..f6f9f65c6 100644
--- a/frontend/src/app/[locale]/subscribe/confirmation/page.tsx
+++ b/frontend/src/app/[locale]/subscribe/confirmation/page.tsx
@@ -5,14 +5,14 @@ import { LocalizedPageProps } from "src/types/intl";
import { useTranslations } from "next-intl";
import { getTranslations, setRequestLocale } from "next-intl/server";
import Link from "next/link";
+import { use } from "react";
import { Grid, GridContainer } from "@trussworks/react-uswds";
import BetaAlert from "src/components/BetaAlert";
import Breadcrumbs from "src/components/Breadcrumbs";
-export async function generateMetadata({
- params: { locale },
-}: LocalizedPageProps) {
+export async function generateMetadata({ params }: LocalizedPageProps) {
+ const { locale } = await params;
const t = await getTranslations({ locale });
const meta: Metadata = {
title: t("Subscribe.page_title"),
@@ -23,8 +23,9 @@ export async function generateMetadata({
}
export default function SubscriptionConfirmation({
- params: { locale },
+ params,
}: LocalizedPageProps) {
+ const { locale } = use(params);
setRequestLocale(locale);
const t = useTranslations("Subscription_confirmation");
diff --git a/frontend/src/app/[locale]/subscribe/page.tsx b/frontend/src/app/[locale]/subscribe/page.tsx
index a9d9d65f5..94446c96e 100644
--- a/frontend/src/app/[locale]/subscribe/page.tsx
+++ b/frontend/src/app/[locale]/subscribe/page.tsx
@@ -4,15 +4,15 @@ import { LocalizedPageProps } from "src/types/intl";
import { useTranslations } from "next-intl";
import { getTranslations, setRequestLocale } from "next-intl/server";
+import { use } from "react";
import { Grid, GridContainer } from "@trussworks/react-uswds";
import BetaAlert from "src/components/BetaAlert";
import Breadcrumbs from "src/components/Breadcrumbs";
import SubscriptionForm from "src/components/subscribe/SubscriptionForm";
-export async function generateMetadata({
- params: { locale },
-}: LocalizedPageProps) {
+export async function generateMetadata({ params }: LocalizedPageProps) {
+ const { locale } = await params;
const t = await getTranslations({ locale });
const meta: Metadata = {
title: t("Subscribe.page_title"),
@@ -22,7 +22,8 @@ export async function generateMetadata({
return meta;
}
-export default function Subscribe({ params: { locale } }: LocalizedPageProps) {
+export default function Subscribe({ params }: LocalizedPageProps) {
+ const { locale } = use(params);
setRequestLocale(locale);
const t = useTranslations("Subscribe");
diff --git a/frontend/src/app/[locale]/subscribe/unsubscribe/page.tsx b/frontend/src/app/[locale]/subscribe/unsubscribe/page.tsx
index 3fd60301e..8e5e39fff 100644
--- a/frontend/src/app/[locale]/subscribe/unsubscribe/page.tsx
+++ b/frontend/src/app/[locale]/subscribe/unsubscribe/page.tsx
@@ -5,14 +5,14 @@ import { LocalizedPageProps } from "src/types/intl";
import { useTranslations } from "next-intl";
import { getTranslations, setRequestLocale } from "next-intl/server";
import Link from "next/link";
+import { use } from "react";
import { Grid, GridContainer } from "@trussworks/react-uswds";
import BetaAlert from "src/components/BetaAlert";
import Breadcrumbs from "src/components/Breadcrumbs";
-export async function generateMetadata({
- params: { locale },
-}: LocalizedPageProps) {
+export async function generateMetadata({ params }: LocalizedPageProps) {
+ const { locale } = await params;
const t = await getTranslations({ locale });
const meta: Metadata = {
title: t("Subscribe.page_title"),
@@ -22,9 +22,8 @@ export async function generateMetadata({
return meta;
}
-export default function Unsubscribe({
- params: { locale },
-}: LocalizedPageProps) {
+export default function Unsubscribe({ params }: LocalizedPageProps) {
+ const { locale } = use(params);
setRequestLocale(locale);
const t = useTranslations("Unsubscription_confirmation");
diff --git a/frontend/src/app/[locale]/user/page.tsx b/frontend/src/app/[locale]/user/page.tsx
index 31064ef63..7dbf34a30 100644
--- a/frontend/src/app/[locale]/user/page.tsx
+++ b/frontend/src/app/[locale]/user/page.tsx
@@ -6,9 +6,8 @@ import { GridContainer } from "@trussworks/react-uswds";
import { LogoutButton } from "./LogoutButton";
-export async function generateMetadata({
- params: { locale },
-}: LocalizedPageProps) {
+export async function generateMetadata({ params }: LocalizedPageProps) {
+ const { locale } = await params;
const t = await getTranslations({ locale });
const meta: Metadata = {
title: t("User.pageTitle"),
@@ -25,11 +24,12 @@ export async function generateMetadata({
// response in the client.
export default async function UserDisplay({
searchParams,
- params: { locale },
-}: LocalizedPageProps & { searchParams: { message?: string } }) {
- const { message } = searchParams;
-
+ params,
+}: LocalizedPageProps & { searchParams: Promise<{ message?: string }> }) {
+ const { message } = await searchParams;
+ const { locale } = await params;
const t = await getTranslations({ locale, namespace: "User" });
+
return (
{t("heading")}
diff --git a/frontend/src/app/api/auth/logout/route.ts b/frontend/src/app/api/auth/logout/route.ts
index ec6247aa3..cad8fa65e 100644
--- a/frontend/src/app/api/auth/logout/route.ts
+++ b/frontend/src/app/api/auth/logout/route.ts
@@ -14,7 +14,7 @@ export async function POST() {
throw new Error("No logout response from API");
}
// delete session from current cookies
- deleteSession();
+ await deleteSession();
return Response.json({ message: "logout success" });
} catch (e) {
const error = e as Error;
diff --git a/frontend/src/components/Header.tsx b/frontend/src/components/Header.tsx
index e96f14053..92426718c 100644
--- a/frontend/src/components/Header.tsx
+++ b/frontend/src/components/Header.tsx
@@ -1,10 +1,11 @@
"use client";
import clsx from "clsx";
+import GrantsLogo from "public/img/grants-logo.png";
import { useFeatureFlags } from "src/hooks/useFeatureFlags";
-import { assetPath } from "src/utils/assetPath";
import { useTranslations } from "next-intl";
+import Image from "next/image";
import Link from "next/link";
import { usePathname } from "next/navigation";
import { useCallback, useEffect, useMemo, useState } from "react";
@@ -29,8 +30,6 @@ type Props = {
const homeRegexp = /^\/(?:e[ns])?$/;
-const logoPath = "./img/grants-logo.svg";
-
const NavLinks = ({
mobileExpanded,
onToggleMobileNav,
@@ -173,13 +172,12 @@ const Header = ({ locale }: Props) => {
- {logoPath && (
-
- )}
+
diff --git a/frontend/src/components/Loading.tsx b/frontend/src/components/Loading.tsx
index 8e7da1e5a..113532d33 100644
--- a/frontend/src/components/Loading.tsx
+++ b/frontend/src/components/Loading.tsx
@@ -1,5 +1,3 @@
-import React from "react";
-
import Spinner from "src/components/Spinner";
export interface LoadingProps {
diff --git a/frontend/src/components/NofoImageLink.tsx b/frontend/src/components/NofoImageLink.tsx
deleted file mode 100644
index ca4062c88..000000000
--- a/frontend/src/components/NofoImageLink.tsx
+++ /dev/null
@@ -1,41 +0,0 @@
-import { pdf } from "src/constants/nofoPdfs";
-import { assetPath } from "src/utils/assetPath";
-
-import Image from "next/image";
-import Link from "next/link";
-import { Grid } from "@trussworks/react-uswds";
-
-const gridCLassName = (portrait: boolean) => {
- return `margin-bottom-4 tablet-lg:flex-${portrait ? "3" : "4"} tablet:order-${
- portrait ? "first" : "last"
- } tablet-lg:order-initial`;
-};
-
-const NofoImageLink = ({ file, image, alt, width, height }: pdf) => {
- const portrait = height > width;
-
- return (
-
-
-
-
-
- );
-};
-
-export default NofoImageLink;
diff --git a/frontend/src/components/content/FundingContent.tsx b/frontend/src/components/content/FundingContent.tsx
deleted file mode 100644
index 6a95fc05b..000000000
--- a/frontend/src/components/content/FundingContent.tsx
+++ /dev/null
@@ -1,70 +0,0 @@
-import { nofoPdfs } from "src/constants/nofoPdfs";
-
-import { useTranslations } from "next-intl";
-import { Grid, GridContainer } from "@trussworks/react-uswds";
-
-import NofoImageLink from "src/components/NofoImageLink";
-
-const FundingContent = () => {
- const t = useTranslations("Index");
-
- return (
-
-
-
- {t("fo_title")}
-
-
-
-
- {t("fo_paragraph_1")}
-
-
-
-
- {t("fo_paragraph_2")}
-
-
-
-
-
- {t("fo_title_2")}
-
-
- {t("fo_paragraph_3")}
-
-
- {nofoPdfs.map((pdf) => (
-
- ))}
-
-
-
-
-
- {t("fo_title_3")}
-
- {t("fo_paragraph_4")}
-
-
-
- {t("fo_title_4")}
-
-
- {t("fo_paragraph_5")}
-
-
-
-
-
- );
-};
-
-export default FundingContent;
diff --git a/frontend/src/components/subscribe/SubscriptionForm.tsx b/frontend/src/components/subscribe/SubscriptionForm.tsx
index 6811cbe8c..510bde850 100644
--- a/frontend/src/components/subscribe/SubscriptionForm.tsx
+++ b/frontend/src/components/subscribe/SubscriptionForm.tsx
@@ -1,10 +1,9 @@
"use client";
-import { useFormState } from "react-dom";
import { subscribeEmail } from "src/app/[locale]/subscribe/actions";
import { useTranslations } from "next-intl";
-import React from "react";
+import React, { useActionState } from "react";
import {
ErrorMessage,
FormGroup,
@@ -22,7 +21,7 @@ export type ValidationErrors = {
export default function SubscriptionForm() {
const t = useTranslations("Subscribe");
- const [state, formAction] = useFormState(subscribeEmail, {
+ const [state, formAction] = useActionState(subscribeEmail, {
errorMessage: "",
validationErrors: {},
});
diff --git a/frontend/src/hoc/withFeatureFlag.tsx b/frontend/src/hoc/withFeatureFlag.tsx
index d0e0cbf09..6d690f20e 100644
--- a/frontend/src/hoc/withFeatureFlag.tsx
+++ b/frontend/src/hoc/withFeatureFlag.tsx
@@ -20,16 +20,17 @@ const withFeatureFlag = (
}
// top level component to grab search params from the top level page props
- const ComponentWithFeatureFlagAndSearchParams = (
+ const ComponentWithFeatureFlagAndSearchParams = async (
props: P & WithFeatureFlagProps,
) => {
- const searchParams = props.searchParams || {};
+ const searchParams = (await props.searchParams) || {};
+ const cookiesRead = await cookies();
const ComponentWithFeatureFlag = (props: P & WithFeatureFlagProps) => {
if (
featureFlagsManager.isFeatureEnabled(
featureFlagName,
- cookies(),
- props.searchParams,
+ cookiesRead,
+ searchParams,
)
) {
onEnabled();
@@ -38,7 +39,9 @@ const withFeatureFlag =
(
return ;
};
- return ;
+ return (
+
+ );
};
return ComponentWithFeatureFlagAndSearchParams;
diff --git a/frontend/src/i18n/request.ts b/frontend/src/i18n/request.ts
index dc62138bb..e3bd41bcd 100644
--- a/frontend/src/i18n/request.ts
+++ b/frontend/src/i18n/request.ts
@@ -21,6 +21,7 @@ export default getRequestConfig(async ({ requestLocale }) => {
locale = defaultLocale;
}
return {
+ locale,
formats,
messages: await getMessagesWithFallbacks(locale),
timeZone,
diff --git a/frontend/src/services/auth/session.ts b/frontend/src/services/auth/session.ts
index a8b3e3685..f3639fe31 100644
--- a/frontend/src/services/auth/session.ts
+++ b/frontend/src/services/auth/session.ts
@@ -61,7 +61,8 @@ export const createSession = async (token: string) => {
}
const expiresAt = newExpirationDate();
const session = await encrypt(token, expiresAt, clientJwtKey);
- cookies().set("session", session, {
+ const cookie = await cookies();
+ cookie.set("session", session, {
httpOnly: true,
secure: environment.ENVIRONMENT === "prod",
expires: expiresAt,
@@ -76,9 +77,10 @@ export const getSession = async (): Promise => {
if (!clientJwtKey || !loginGovJwtKey) {
initializeSessionSecrets();
}
- const cookie = cookies().get("session")?.value;
- if (!cookie) return null;
- const payload = await decryptClientToken(cookie);
+ const cookie = await cookies();
+ const sessionToken = cookie.get("session")?.value;
+ if (!sessionToken) return null;
+ const payload = await decryptClientToken(sessionToken);
if (!payload) {
return null;
}
diff --git a/frontend/src/services/auth/sessionUtils.ts b/frontend/src/services/auth/sessionUtils.ts
index 991acc3c7..4c59173b1 100644
--- a/frontend/src/services/auth/sessionUtils.ts
+++ b/frontend/src/services/auth/sessionUtils.ts
@@ -41,6 +41,7 @@ export const encrypt = async (
return jwt;
};
-export function deleteSession() {
- cookies().delete("session");
+export async function deleteSession() {
+ const cookie = await cookies();
+ cookie.delete("session");
}
diff --git a/frontend/src/services/search/SearchFilterManager.ts b/frontend/src/services/search/SearchFilterManager.ts
index 3358eab5d..12a397bbc 100644
--- a/frontend/src/services/search/SearchFilterManager.ts
+++ b/frontend/src/services/search/SearchFilterManager.ts
@@ -13,13 +13,13 @@ export default class SearchFilterManager {
options: FilterOption[];
setOptions: React.Dispatch>;
updateQueryParams: UpdateQueryParamsFunction;
- formRef: React.RefObject;
+ formRef: React.RefObject;
constructor(
options: FilterOption[],
setOptions: React.Dispatch>,
updateQueryParams: UpdateQueryParamsFunction,
- formRef: React.RefObject,
+ formRef: React.RefObject,
) {
this.options = options;
this.setOptions = setOptions;
diff --git a/frontend/src/styles/_uswds-theme.scss b/frontend/src/styles/_uswds-theme.scss
index 36496a818..9a4c3b167 100644
--- a/frontend/src/styles/_uswds-theme.scss
+++ b/frontend/src/styles/_uswds-theme.scss
@@ -19,8 +19,7 @@ in the form $setting: value,
$utilities-use-important: true,
// Layout & grid settings
- $theme-utility-breakpoints:
- (
+ $theme-utility-breakpoints: (
"card": false,
"card-lg": false,
"mobile": false,
@@ -85,8 +84,7 @@ in the form $setting: value,
$theme-lead-font-family: "body",
// Color settings
- $background-color-palettes:
- (
+ $background-color-palettes: (
"palette-color-system-cyan-light",
"palette-color-system-yellow-light",
"palette-color-system-green-cool",
diff --git a/frontend/src/types/intl.ts b/frontend/src/types/intl.ts
index ed17560f9..d9cd76263 100644
--- a/frontend/src/types/intl.ts
+++ b/frontend/src/types/intl.ts
@@ -5,4 +5,4 @@ export type TFn =
| ReturnType>
| Awaited>>;
-export type LocalizedPageProps = { params: { locale: string } };
+export type LocalizedPageProps = { params: Promise<{ locale: string }> };
diff --git a/frontend/src/types/uiTypes.ts b/frontend/src/types/uiTypes.ts
index c8ce95a4f..f360463c8 100644
--- a/frontend/src/types/uiTypes.ts
+++ b/frontend/src/types/uiTypes.ts
@@ -13,7 +13,7 @@ export enum Breakpoints {
}
export type WithFeatureFlagProps = {
- searchParams: ServerSideSearchParams;
+ searchParams: Promise;
};
export interface ErrorProps {
diff --git a/frontend/src/utils/assetPath.ts b/frontend/src/utils/assetPath.ts
deleted file mode 100644
index 6eb29bea2..000000000
--- a/frontend/src/utils/assetPath.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-import { environment } from "src/constants/environments";
-
-export function assetPath(relativePath: string) {
- return `${environment.NEXT_PUBLIC_BASE_PATH}${relativePath}`;
-}
diff --git a/frontend/src/utils/testing/intlMocks.ts b/frontend/src/utils/testing/intlMocks.ts
index 9842e7a74..82b41d87c 100644
--- a/frontend/src/utils/testing/intlMocks.ts
+++ b/frontend/src/utils/testing/intlMocks.ts
@@ -10,6 +10,10 @@ export function useTranslationsMock() {
return mockUseTranslations as TFn;
}
+export const localeParams = new Promise<{ locale: string }>((resolve) => {
+ resolve({ locale: "en" });
+});
+
// mocking all types of messages, could split by message type in the future
export const mockMessages = {
Process: {
diff --git a/frontend/stories/components/FundingContent.stories.tsx b/frontend/stories/components/FundingContent.stories.tsx
deleted file mode 100644
index 42f509f69..000000000
--- a/frontend/stories/components/FundingContent.stories.tsx
+++ /dev/null
@@ -1,18 +0,0 @@
-import { Meta } from "@storybook/react";
-
-import FundingContent from "src/components/content/FundingContent";
-
-const meta: Meta = {
- title: "Components/Content/Funding Content",
- component: FundingContent,
-};
-export default meta;
-
-export const Default = {
- parameters: {
- design: {
- type: "figma",
- url: "https://www.figma.com/file/lpKPdyTyLJB5JArxhGjJnE/beta.grants.gov?type=design&node-id=14-907&mode=design&t=gEXdEnzZUfuODXut-4",
- },
- },
-};
diff --git a/frontend/stories/components/NofoImageLink.stories.tsx b/frontend/stories/components/NofoImageLink.stories.tsx
deleted file mode 100644
index 768df5f48..000000000
--- a/frontend/stories/components/NofoImageLink.stories.tsx
+++ /dev/null
@@ -1,24 +0,0 @@
-import { Meta, StoryObj } from "@storybook/react";
-
-import NofoImageLink from "src/components/NofoImageLink";
-
-const meta: Meta = {
- title: "Components/Nofo Image Link",
- component: NofoImageLink,
-};
-export default meta;
-type Story = StoryObj;
-
-export const Primary: Story = {
- parameters: {
- design: {
- type: "figma",
- url: "https://www.figma.com/file/lpKPdyTyLJB5JArxhGjJnE/beta.grants.gov?type=design&node-id=86-600&mode=design&t=gEXdEnzZUfuODXut-4",
- },
- },
- args: {
- file: "/docs/acl_prototype.pdf",
- image: "/img/acl_prototype.png",
- alt: "This should be a key in i18n",
- },
-};
diff --git a/frontend/tests/components/ContentDisplayToggle.test.tsx b/frontend/tests/components/ContentDisplayToggle.test.tsx
index 900543a7a..ed1fa1f69 100644
--- a/frontend/tests/components/ContentDisplayToggle.test.tsx
+++ b/frontend/tests/components/ContentDisplayToggle.test.tsx
@@ -73,6 +73,7 @@ describe("ContentDisplayToggle", () => {
// this test is basically useless, as it is only asserting that classes are being applied
// all of these tests are not great, but it seems that uswds styling is not being loaded by
// testing library / jsdom, so the ability to test based on actual user facing visibility is heavily limited
+ // eslint-disable-next-line jest/no-disabled-tests
it.skip("Toggles responds by hiding button and displaying content above passed breakpoint", () => {
render(
{
- it("Renders without errors", () => {
- render();
- const fundingH2 = screen.getByRole("heading", {
- level: 2,
- name: /Improvements to funding opportunity announcements?/i,
- });
-
- expect(fundingH2).toBeInTheDocument();
- });
-});
diff --git a/frontend/tests/components/NofoImageLink.test.tsx b/frontend/tests/components/NofoImageLink.test.tsx
deleted file mode 100644
index f4a12b843..000000000
--- a/frontend/tests/components/NofoImageLink.test.tsx
+++ /dev/null
@@ -1,33 +0,0 @@
-import { render, screen } from "@testing-library/react";
-
-import NofoImageLink from "src/components/NofoImageLink";
-
-describe("PdfContainer", () => {
- it("Renders landscape without errors", () => {
- render(
- ,
- );
- const alt = screen.getByAltText("test alt content");
- expect(alt).toBeInTheDocument();
- });
-
- it("Renders portrait without errors", () => {
- render(
- ,
- );
- const alt = screen.getByAltText("test alt content");
- expect(alt).toBeInTheDocument();
- });
-});
diff --git a/frontend/tests/components/search/SearchResultsListItem.test.tsx b/frontend/tests/components/search/SearchResultsListItem.test.tsx
index 576ee2ec9..5e01a1787 100644
--- a/frontend/tests/components/search/SearchResultsListItem.test.tsx
+++ b/frontend/tests/components/search/SearchResultsListItem.test.tsx
@@ -1,6 +1,6 @@
import { axe } from "jest-axe";
import { Opportunity } from "src/types/search/searchResponseTypes";
-import { render, screen } from "tests/react-utils";
+import { render, screen, waitFor } from "tests/react-utils";
import React from "react";
@@ -26,7 +26,7 @@ describe("SearchResultsListItem", () => {
const { container } = render(
,
);
- const results = await axe(container);
+ const results = await waitFor(() => axe(container));
expect(results).toHaveNoViolations();
});
diff --git a/frontend/tests/pages/dev/feature-flags/page.test.tsx b/frontend/tests/pages/dev/feature-flags/page.test.tsx
index 3f3dbddd4..7cd45e3aa 100644
--- a/frontend/tests/pages/dev/feature-flags/page.test.tsx
+++ b/frontend/tests/pages/dev/feature-flags/page.test.tsx
@@ -25,6 +25,13 @@ const mockSetFeatureFlag = jest.fn(
},
);
+jest.mock("react", () => ({
+ ...jest.requireActual("react"),
+ use: jest.fn(() => ({
+ locale: "en",
+ })),
+}));
+
jest.mock("src/hooks/useFeatureFlags", () => ({
useFeatureFlags: () => mockUseFeatureFlags(),
}));
diff --git a/frontend/tests/pages/maintenance/page.test.tsx b/frontend/tests/pages/maintenance/page.test.tsx
index fa68a3db2..06021172f 100644
--- a/frontend/tests/pages/maintenance/page.test.tsx
+++ b/frontend/tests/pages/maintenance/page.test.tsx
@@ -2,13 +2,24 @@ import { render, screen, waitFor } from "@testing-library/react";
import { axe } from "jest-axe";
import { identity } from "lodash";
import Maintenance from "src/app/[locale]/maintenance/page";
-import { mockMessages, useTranslationsMock } from "src/utils/testing/intlMocks";
+import {
+ localeParams,
+ mockMessages,
+ useTranslationsMock,
+} from "src/utils/testing/intlMocks";
jest.mock("next-intl/server", () => ({
getTranslations: () => identity,
setRequestLocale: identity,
}));
+jest.mock("react", () => ({
+ ...jest.requireActual("react"),
+ use: jest.fn(() => ({
+ locale: "en",
+ })),
+}));
+
jest.mock("next-intl", () => ({
useTranslations: () => useTranslationsMock(),
useMessages: () => mockMessages,
@@ -16,7 +27,7 @@ jest.mock("next-intl", () => ({
describe("Maintenance", () => {
it("renders intro text", () => {
- render();
+ render();
const content = screen.getByText("heading");
@@ -24,7 +35,7 @@ describe("Maintenance", () => {
});
it("passes accessibility scan", async () => {
- const { container } = render();
+ const { container } = render();
const results = await waitFor(() => axe(container));
expect(results).toHaveNoViolations();
diff --git a/frontend/tests/pages/not-found.test.tsx b/frontend/tests/pages/not-found.test.tsx
index 22110d7e5..ff0c6487c 100644
--- a/frontend/tests/pages/not-found.test.tsx
+++ b/frontend/tests/pages/not-found.test.tsx
@@ -4,6 +4,13 @@ import { identity } from "lodash";
import PageNotFound from "src/app/[locale]/not-found";
import { useTranslationsMock } from "src/utils/testing/intlMocks";
+jest.mock("react", () => ({
+ ...jest.requireActual("react"),
+ use: jest.fn(() => ({
+ locale: "en",
+ })),
+}));
+
jest.mock("next-intl/server", () => ({
getTranslations: () => identity,
unstable_setRequestLocale: identity,
diff --git a/frontend/tests/pages/page.test.tsx b/frontend/tests/pages/page.test.tsx
index 4a75d07e7..ee02304b5 100644
--- a/frontend/tests/pages/page.test.tsx
+++ b/frontend/tests/pages/page.test.tsx
@@ -2,7 +2,18 @@ import { render, screen, waitFor } from "@testing-library/react";
import { axe } from "jest-axe";
import { identity } from "lodash";
import Home from "src/app/[locale]/page";
-import { mockMessages, useTranslationsMock } from "src/utils/testing/intlMocks";
+import {
+ localeParams,
+ mockMessages,
+ useTranslationsMock,
+} from "src/utils/testing/intlMocks";
+
+jest.mock("react", () => ({
+ ...jest.requireActual("react"),
+ use: jest.fn(() => ({
+ locale: "en",
+ })),
+}));
jest.mock("next-intl/server", () => ({
getTranslations: () => identity,
@@ -16,7 +27,7 @@ jest.mock("next-intl", () => ({
describe("Home", () => {
it("renders intro text", () => {
- render(Home({ params: { locale: "en" } }));
+ render(Home({ params: localeParams }));
const content = screen.getByText("goal.paragraph_1");
@@ -24,7 +35,7 @@ describe("Home", () => {
});
it("passes accessibility scan", async () => {
- const { container } = render(Home({ params: { locale: "en" } }));
+ const { container } = render(Home({ params: localeParams }));
const results = await waitFor(() => axe(container));
expect(results).toHaveNoViolations();
diff --git a/frontend/tests/pages/process/page.test.tsx b/frontend/tests/pages/process/page.test.tsx
index b0e344e5c..13c4c0f5b 100644
--- a/frontend/tests/pages/process/page.test.tsx
+++ b/frontend/tests/pages/process/page.test.tsx
@@ -2,7 +2,18 @@ import { render, screen, waitFor } from "@testing-library/react";
import { axe } from "jest-axe";
import { identity } from "lodash";
import Process from "src/app/[locale]/process/page";
-import { mockMessages, useTranslationsMock } from "src/utils/testing/intlMocks";
+import {
+ localeParams,
+ mockMessages,
+ useTranslationsMock,
+} from "src/utils/testing/intlMocks";
+
+jest.mock("react", () => ({
+ ...jest.requireActual("react"),
+ use: jest.fn(() => ({
+ locale: "en",
+ })),
+}));
jest.mock("next-intl/server", () => ({
getTranslations: () => identity,
@@ -16,17 +27,14 @@ jest.mock("next-intl", () => ({
describe("Process", () => {
it("renders intro text", () => {
- render(Process({ params: { locale: "en" } }));
-
+ render();
const content = screen.getByText("intro.content");
-
expect(content).toBeInTheDocument();
});
it("passes accessibility scan", async () => {
- const { container } = render(Process({ params: { locale: "en" } }));
+ const { container } = render();
const results = await waitFor(() => axe(container));
-
expect(results).toHaveNoViolations();
});
});
diff --git a/frontend/tests/pages/research/page.test.tsx b/frontend/tests/pages/research/page.test.tsx
index 4a8daf9c2..1227d0a8f 100644
--- a/frontend/tests/pages/research/page.test.tsx
+++ b/frontend/tests/pages/research/page.test.tsx
@@ -2,7 +2,18 @@ import { render, screen, waitFor } from "@testing-library/react";
import { axe } from "jest-axe";
import { identity } from "lodash";
import Research from "src/app/[locale]/research/page";
-import { mockMessages, useTranslationsMock } from "src/utils/testing/intlMocks";
+import {
+ localeParams,
+ mockMessages,
+ useTranslationsMock,
+} from "src/utils/testing/intlMocks";
+
+jest.mock("react", () => ({
+ ...jest.requireActual("react"),
+ use: jest.fn(() => ({
+ locale: "en",
+ })),
+}));
jest.mock("next-intl/server", () => ({
getTranslations: () => identity,
@@ -16,7 +27,7 @@ jest.mock("next-intl", () => ({
describe("Research", () => {
it("renders intro text", () => {
- render(Research({ params: { locale: "en" } }));
+ render(Research({ params: localeParams }));
const content = screen.getByText("intro.content");
@@ -24,7 +35,7 @@ describe("Research", () => {
});
it("passes accessibility scan", async () => {
- const { container } = render(Research({ params: { locale: "en" } }));
+ const { container } = render(Research({ params: localeParams }));
const results = await waitFor(() => axe(container));
expect(results).toHaveNoViolations();
diff --git a/frontend/tests/pages/search/page.test.tsx b/frontend/tests/pages/search/page.test.tsx
index 7d23a1d4b..338fd8af4 100644
--- a/frontend/tests/pages/search/page.test.tsx
+++ b/frontend/tests/pages/search/page.test.tsx
@@ -54,6 +54,7 @@ jest.mock("react", () => ({
...jest.requireActual("react"),
Suspense: ({ fallback }: { fallback: React.Component }) => fallback,
cache: (fn: unknown) => fn,
+ use: jest.fn((e: { [key: string]: string }) => e),
}));
const fetchMock = jest.fn().mockResolvedValue({
diff --git a/frontend/tests/pages/subscribe/page.test.tsx b/frontend/tests/pages/subscribe/page.test.tsx
index c1c77e534..8ae972861 100644
--- a/frontend/tests/pages/subscribe/page.test.tsx
+++ b/frontend/tests/pages/subscribe/page.test.tsx
@@ -2,7 +2,7 @@ import { render, screen, waitFor } from "@testing-library/react";
import { axe } from "jest-axe";
import { identity } from "lodash";
import Subscribe from "src/app/[locale]/subscribe/page";
-import { useTranslationsMock } from "src/utils/testing/intlMocks";
+import { localeParams, useTranslationsMock } from "src/utils/testing/intlMocks";
jest.mock("react-dom", () => {
const originalModule =
@@ -30,6 +30,13 @@ jest.mock("react-dom", () => {
};
});
+jest.mock("react", () => ({
+ ...jest.requireActual("react"),
+ use: jest.fn(() => ({
+ locale: "en",
+ })),
+}));
+
jest.mock("next-intl", () => ({
useTranslations: () => useTranslationsMock(),
}));
@@ -41,7 +48,7 @@ jest.mock("next-intl/server", () => ({
describe("Subscribe", () => {
it("renders intro text", () => {
- render(Subscribe({ params: { locale: "en" } }));
+ render(Subscribe({ params: localeParams }));
const content = screen.getByText("intro");
@@ -49,7 +56,7 @@ describe("Subscribe", () => {
});
it("passes accessibility scan", async () => {
- const { container } = render(Subscribe({ params: { locale: "en" } }));
+ const { container } = render(Subscribe({ params: localeParams }));
const results = await waitFor(() => axe(container));
expect(results).toHaveNoViolations();
diff --git a/frontend/tests/pages/user/page.test.tsx b/frontend/tests/pages/user/page.test.tsx
new file mode 100644
index 000000000..06ca76d2c
--- /dev/null
+++ b/frontend/tests/pages/user/page.test.tsx
@@ -0,0 +1,30 @@
+import { render, screen } from "@testing-library/react";
+import { identity } from "lodash";
+import UserDisplay from "src/app/[locale]/user/page";
+import { localeParams } from "src/utils/testing/intlMocks";
+
+jest.mock("next-intl/server", () => ({
+ getTranslations: () => identity,
+}));
+
+jest.mock("next/navigation", () => ({
+ useRouter: () => ({
+ push: () => null,
+ }),
+}));
+
+const searchParams = (query: { [key: string]: string }) =>
+ new Promise<{ [key: string]: string }>((resolve) => {
+ resolve(query);
+ });
+
+describe("User Page", () => {
+ test("It renders", async () => {
+ const component = await UserDisplay({
+ params: localeParams,
+ searchParams: searchParams({ message: "success" }),
+ });
+ render(component);
+ expect(screen.getByText(/success/i)).toBeInTheDocument();
+ });
+});
diff --git a/frontend/tests/services/auth/session.test.ts b/frontend/tests/services/auth/session.test.ts
index 952ae9e4f..f1def1d23 100644
--- a/frontend/tests/services/auth/session.test.ts
+++ b/frontend/tests/services/auth/session.test.ts
@@ -96,6 +96,7 @@ describe("getSession", () => {
describe("createSession", () => {
afterEach(() => jest.clearAllMocks());
// to get this to work we'd need to manage resetting all modules before the test, which is a bit of a pain
+ // eslint-disable-next-line jest/no-disabled-tests
it.skip("initializes session secrets if necessary", async () => {
await createSession("nothingSpecial");
expect(encodeTextMock).toHaveBeenCalledWith("session secret");
diff --git a/frontend/tests/services/auth/sessionUtils.test.ts b/frontend/tests/services/auth/sessionUtils.test.ts
index a43884875..4055f08a5 100644
--- a/frontend/tests/services/auth/sessionUtils.test.ts
+++ b/frontend/tests/services/auth/sessionUtils.test.ts
@@ -67,8 +67,8 @@ jest.mock("jose", () => ({
describe("deleteSession", () => {
afterEach(() => jest.clearAllMocks());
- it("calls cookie.delete with expected values", () => {
- deleteSession();
+ it("calls cookie.delete with expected values", async () => {
+ await deleteSession();
expect(deleteCookiesMock).toHaveBeenCalledTimes(1);
expect(deleteCookiesMock).toHaveBeenCalledWith("session");
});
diff --git a/frontend/tests/services/featureFlags/featureFlagHelpers.test.ts b/frontend/tests/services/featureFlags/featureFlagHelpers.test.ts
index c17be671d..aa9218eab 100644
--- a/frontend/tests/services/featureFlags/featureFlagHelpers.test.ts
+++ b/frontend/tests/services/featureFlags/featureFlagHelpers.test.ts
@@ -58,6 +58,7 @@ describe("getFeatureFlagsFromCookie", () => {
});
// // do we still need to support this?
+ // eslint-disable-next-line jest/no-disabled-tests, jest/no-commented-out-tests
// test("getter loads feature flags with server-side getServerSideProps cookies", () => {
// const cookieRecord = {
// // Was unable to override flag keys. Use feature flag class invocation default for now.
diff --git a/frontend/tests/services/withFeatureFlag.test.tsx b/frontend/tests/services/withFeatureFlag.test.tsx
index 32eecb29a..bc6c473ac 100644
--- a/frontend/tests/services/withFeatureFlag.test.tsx
+++ b/frontend/tests/services/withFeatureFlag.test.tsx
@@ -1,4 +1,3 @@
-// import Cookies from "js-cookie";
import Cookies from "js-cookie";
import { identity } from "lodash";
import withFeatureFlag from "src/hoc/withFeatureFlag";
@@ -22,6 +21,11 @@ jest.mock("next/headers", () => ({
cookies: () => Cookies,
}));
+const searchPromise = (query: { [key: string]: string }) =>
+ new Promise<{ [key: string]: string }>((resolve) => {
+ resolve(query);
+ });
+
describe("WithFeatureFlag", () => {
afterEach(() => {
enableFeature = false;
@@ -29,7 +33,7 @@ describe("WithFeatureFlag", () => {
afterAll(() => {
jest.restoreAllMocks();
});
- it("adds search params as prop to wrapped component", () => {
+ it("adds search params as prop to wrapped component", async () => {
const OriginalComponent = jest.fn();
const searchParams = { any: "param" };
const WrappedComponent = withFeatureFlag(
@@ -37,13 +41,21 @@ describe("WithFeatureFlag", () => {
"searchOff",
identity,
);
- render();
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+ // @ts-ignore
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
+ const component = await WrappedComponent({
+ searchParams: searchPromise(searchParams),
+ });
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
+ render(component);
expect(OriginalComponent).toHaveBeenCalledTimes(1);
-
- // not sure what the second arg represents here but let's forget about it for now
- expect(OriginalComponent).toHaveBeenCalledWith({ searchParams }, {});
+ expect(OriginalComponent).toHaveBeenCalledWith(
+ { searchParams: searchPromise(searchParams) },
+ undefined,
+ );
});
- it("calls onEnabled during wrapped component render when feature flag is enabled", () => {
+ it("calls onEnabled during wrapped component render when feature flag is enabled", async () => {
enableFeature = true;
const OriginalComponent = jest.fn();
const onEnabled = jest.fn();
@@ -53,19 +65,14 @@ describe("WithFeatureFlag", () => {
"searchOff",
onEnabled,
);
- render();
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+ // @ts-ignore
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
+ const component = await WrappedComponent({
+ searchParams: searchPromise(searchParams),
+ });
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
+ render(component);
expect(onEnabled).toHaveBeenCalledTimes(1);
});
- it("does not call onEnabled during wrapped component render when feature flag is not enabled", () => {
- const OriginalComponent = jest.fn();
- const onEnabled = jest.fn();
- const searchParams = { any: "param" };
- const WrappedComponent = withFeatureFlag(
- OriginalComponent,
- "searchOff",
- onEnabled,
- );
- render();
- expect(onEnabled).toHaveBeenCalledTimes(0);
- });
});