diff --git a/services/ui-src/src/components/accordions/AccordionItem.test.tsx b/services/ui-src/src/components/accordions/AccordionItem.test.tsx index 12f8d15c2..ee40741e5 100644 --- a/services/ui-src/src/components/accordions/AccordionItem.test.tsx +++ b/services/ui-src/src/components/accordions/AccordionItem.test.tsx @@ -1,11 +1,12 @@ import { render, screen } from "@testing-library/react"; -import { axe } from "jest-axe"; import userEvent from "@testing-library/user-event"; -// utils -import { RouterWrappedComponent } from "utils/testing/setupJest"; // components import { Accordion } from "@chakra-ui/react"; import { AccordionItem } from "components"; +// utils +import { RouterWrappedComponent } from "utils/testing/setupJest"; +import { testA11y } from "utils/testing/commonTests"; +// verbiage import verbiage from "verbiage/pages/home"; const accordionItemComponent = ( @@ -16,7 +17,7 @@ const accordionItemComponent = ( ); -describe("Test AccordionItem", () => { +describe("", () => { beforeEach(() => { render(accordionItemComponent); }); @@ -37,12 +38,6 @@ describe("Test AccordionItem", () => { expect(screen.queryByAltText("Expand")).toBeFalsy(); expect(screen.getByAltText("Collapse")).toBeVisible(); }); -}); -describe("Test AccordionItem accessibility", () => { - it("Should not have basic accessibility issues", async () => { - const { container } = render(accordionItemComponent); - const results = await axe(container); - expect(results).toHaveNoViolations(); - }); + testA11y(accordionItemComponent); }); diff --git a/services/ui-src/src/components/accordions/AccordionItem.tsx b/services/ui-src/src/components/accordions/AccordionItem.tsx index 3f4f8d836..592dc045a 100644 --- a/services/ui-src/src/components/accordions/AccordionItem.tsx +++ b/services/ui-src/src/components/accordions/AccordionItem.tsx @@ -36,6 +36,7 @@ export const AccordionItem = ({ label, children, ...props }: Props) => { }; interface Props { + label: string; children?: ReactChild | ReactChild[]; [key: string]: any; } diff --git a/services/ui-src/src/components/accordions/FaqAccordion.test.tsx b/services/ui-src/src/components/accordions/FaqAccordion.test.tsx index 0a3ae9ca2..12fbbb501 100644 --- a/services/ui-src/src/components/accordions/FaqAccordion.test.tsx +++ b/services/ui-src/src/components/accordions/FaqAccordion.test.tsx @@ -1,10 +1,10 @@ import { render, screen } from "@testing-library/react"; -import { axe } from "jest-axe"; import userEvent from "@testing-library/user-event"; -// utils -import { RouterWrappedComponent } from "utils/testing/setupJest"; // components import { FaqAccordion } from "components"; +// utils +import { RouterWrappedComponent } from "utils/testing/setupJest"; +import { testA11y } from "utils/testing/commonTests"; const accordionItems = [ { @@ -19,7 +19,7 @@ const faqAccordionComponent = ( ); -describe("Test FaqAccordion", () => { +describe("", () => { beforeEach(() => { render(faqAccordionComponent); }); @@ -41,12 +41,6 @@ describe("Test FaqAccordion", () => { expect(faqQuestion).toBeVisible(); expect(screen.getByText(accordionItems[0].answer)).toBeVisible(); }); -}); -describe("Test FaqAccordion accessibility", () => { - it("Should not have basic accessibility issues", async () => { - const { container } = render(faqAccordionComponent); - const results = await axe(container); - expect(results).toHaveNoViolations(); - }); + testA11y(faqAccordionComponent); }); diff --git a/services/ui-src/src/components/accordions/InstructionsAccordion.test.tsx b/services/ui-src/src/components/accordions/InstructionsAccordion.test.tsx new file mode 100644 index 000000000..050493a93 --- /dev/null +++ b/services/ui-src/src/components/accordions/InstructionsAccordion.test.tsx @@ -0,0 +1,52 @@ +import { render, screen } from "@testing-library/react"; +import userEvent from "@testing-library/user-event"; +// components +import { InstructionsAccordion } from "components"; +// utils +import { testA11y } from "utils/testing/commonTests"; + +export const mockAccordion = { + buttonLabel: "Instructions", + intro: [ + { + type: "text", + as: "span", + content: "Bold Instructions", + }, + { + type: "text", + as: "span", + content: "More instructions", + }, + ], + list: [`List Item 1`, "List Item 2", `List Item 3`], + text: "Additional Text", +}; + +const accordionComponent = ; + +describe("", () => { + beforeEach(() => { + render(accordionComponent); + }); + + test("Accordion is visible", () => { + expect(screen.getByText(mockAccordion.buttonLabel)).toBeVisible(); + }); + + test("Accordion default closed state only shows the question", () => { + expect(screen.getByText(mockAccordion.buttonLabel)).toBeVisible(); + expect(screen.getByText(mockAccordion.text)).not.toBeVisible(); + }); + + test("Accordion should show answer on click", async () => { + const accordionQuestion = screen.getByText(mockAccordion.buttonLabel); + expect(accordionQuestion).toBeVisible(); + expect(screen.getByText(mockAccordion.text)).not.toBeVisible(); + await userEvent.click(accordionQuestion); + expect(accordionQuestion).toBeVisible(); + expect(screen.getByText(mockAccordion.text)).toBeVisible(); + }); + + testA11y(accordionComponent); +}); diff --git a/services/ui-src/src/components/accordions/TemplateCardAccordion.test.tsx b/services/ui-src/src/components/accordions/TemplateCardAccordion.test.tsx index ab050ada3..2ecd9024e 100644 --- a/services/ui-src/src/components/accordions/TemplateCardAccordion.test.tsx +++ b/services/ui-src/src/components/accordions/TemplateCardAccordion.test.tsx @@ -1,56 +1,43 @@ import { render, screen } from "@testing-library/react"; -import { axe } from "jest-axe"; import userEvent from "@testing-library/user-event"; -// utils -import { RouterWrappedComponent } from "utils/testing/setupJest"; // components import { TemplateCardAccordion } from "components"; +// utils +import { RouterWrappedComponent } from "utils/testing/setupJest"; +import { testA11y } from "utils/testing/commonTests"; +// verbiage import verbiage from "verbiage/pages/home"; +const { buttonLabel, text: accordionText } = verbiage.cards.MCPAR.accordion; + const accordionComponent = ( ); -describe("Test TemplateCardAccordion", () => { +describe("", () => { beforeEach(() => { render(accordionComponent); }); test("Accordion is visible", () => { - expect( - screen.getByText(verbiage.cards.MCPAR.accordion.buttonLabel) - ).toBeVisible(); + expect(screen.getByText(buttonLabel)).toBeVisible(); }); test("Accordion default closed state only shows the question", () => { - expect( - screen.getByText(verbiage.cards.MCPAR.accordion.buttonLabel) - ).toBeVisible(); - expect( - screen.getByText(verbiage.cards.MCPAR.accordion.text) - ).not.toBeVisible(); + expect(screen.getByText(buttonLabel)).toBeVisible(); + expect(screen.getByText(accordionText)).not.toBeVisible(); }); test("Accordion should show answer on click", async () => { - const accordionQuestion = screen.getByText( - verbiage.cards.MCPAR.accordion.buttonLabel - ); + const accordionQuestion = screen.getByText(buttonLabel); expect(accordionQuestion).toBeVisible(); - expect( - screen.getByText(verbiage.cards.MCPAR.accordion.text) - ).not.toBeVisible(); + expect(screen.getByText(accordionText)).not.toBeVisible(); await userEvent.click(accordionQuestion); expect(accordionQuestion).toBeVisible(); - expect(screen.getByText(verbiage.cards.MCPAR.accordion.text)).toBeVisible(); + expect(screen.getByText(accordionText)).toBeVisible(); }); -}); -describe("Test TemplateCardAccordion accessibility", () => { - it("Should not have basic accessibility issues", async () => { - const { container } = render(accordionComponent); - const results = await axe(container); - expect(results).toHaveNoViolations(); - }); + testA11y(accordionComponent); }); diff --git a/services/ui-src/src/components/accordions/TemplateCardAccordion.tsx b/services/ui-src/src/components/accordions/TemplateCardAccordion.tsx index 443a23cbb..bb36c9ae9 100644 --- a/services/ui-src/src/components/accordions/TemplateCardAccordion.tsx +++ b/services/ui-src/src/components/accordions/TemplateCardAccordion.tsx @@ -1,7 +1,7 @@ // components import { Accordion, ListItem, Text, UnorderedList } from "@chakra-ui/react"; import { AccordionItem, Table } from "components"; -// utils +// types import { AnyObject } from "types"; export const TemplateCardAccordion = ({ verbiage, ...props }: Props) => ( diff --git a/services/ui-src/src/components/alerts/Alert.test.tsx b/services/ui-src/src/components/alerts/Alert.test.tsx index 5da153b5e..1efdde331 100644 --- a/services/ui-src/src/components/alerts/Alert.test.tsx +++ b/services/ui-src/src/components/alerts/Alert.test.tsx @@ -1,8 +1,10 @@ import { render, screen } from "@testing-library/react"; -import { axe } from "jest-axe"; -//components +// components import { Alert } from "components"; +// types import { AlertTypes } from "types"; +// utils +import { testA11y } from "utils/testing/commonTests"; const alertComponent = ( ); -describe("Test Alert Item", () => { - beforeEach(() => { - render(alertComponent); - }); - +describe("", () => { test("Alert is visible", () => { + render(alertComponent); expect(screen.getByText("Test alert!")).toBeVisible(); expect(screen.getByText("This is for testing.")).toBeVisible(); expect(screen.getByText("test-link")).toBeVisible(); }); -}); -describe("Test Alert accessibility", () => { - it("Should not have basic accessibility issues", async () => { - const { container } = render(alertComponent); - const results = await axe(container); - expect(results).toHaveNoViolations(); - }); + testA11y(alertComponent); }); diff --git a/services/ui-src/src/components/alerts/Alert.tsx b/services/ui-src/src/components/alerts/Alert.tsx index b65fe4462..54a46dd64 100644 --- a/services/ui-src/src/components/alerts/Alert.tsx +++ b/services/ui-src/src/components/alerts/Alert.tsx @@ -11,12 +11,12 @@ import { } from "@chakra-ui/react"; // types import { AlertTypes, CustomHtmlElement } from "types"; +// utils +import { parseCustomHtml } from "utils"; // assets import alertIcon from "assets/icons/icon_info_circle.png"; import warningIcon from "assets/icons/icon_warning.png"; import errorIcon from "assets/icons/icon_error_circle.png"; -// utils -import { parseCustomHtml } from "utils"; export const Alert = ({ status, diff --git a/services/ui-src/src/components/alerts/ErrorAlert.test.tsx b/services/ui-src/src/components/alerts/ErrorAlert.test.tsx index 49f331237..d96d89e60 100644 --- a/services/ui-src/src/components/alerts/ErrorAlert.test.tsx +++ b/services/ui-src/src/components/alerts/ErrorAlert.test.tsx @@ -1,9 +1,12 @@ import { render, screen } from "@testing-library/react"; -import { axe } from "jest-axe"; -//components +// components import { ErrorAlert } from "components"; -import { genericErrorContent } from "verbiage/errors"; +// types import { ErrorVerbiage } from "types"; +// utils +import { testA11y } from "utils/testing/commonTests"; +// verbiage +import { genericErrorContent } from "verbiage/errors"; const error: ErrorVerbiage = { title: "We've run into a problem", @@ -12,7 +15,7 @@ const error: ErrorVerbiage = { const errorAlertComponent = ; -describe("Test ErrorAlert component", () => { +describe("", () => { beforeEach(() => { render(errorAlertComponent); }); @@ -24,12 +27,6 @@ describe("Test ErrorAlert component", () => { test("ErrorAlert description is visible", () => { expect(screen.getByText(/Something went wrong on our end/)).toBeVisible(); }); -}); -describe("Test ErrorAlert accessibility", () => { - it("Should not have basic accessibility issues", async () => { - const { container } = render(errorAlertComponent); - const results = await axe(container); - expect(results).toHaveNoViolations(); - }); + testA11y(errorAlertComponent); }); diff --git a/services/ui-src/src/components/alerts/ErrorAlert.tsx b/services/ui-src/src/components/alerts/ErrorAlert.tsx index 5d5ea0937..164deea46 100644 --- a/services/ui-src/src/components/alerts/ErrorAlert.tsx +++ b/services/ui-src/src/components/alerts/ErrorAlert.tsx @@ -1,8 +1,8 @@ +import { useRef } from "react"; // components import { Box, Collapse } from "@chakra-ui/react"; import { Alert } from "components"; -import { useRef } from "react"; -// utils +// types import { AlertTypes, AnyObject, ErrorVerbiage } from "types"; export const ErrorAlert = ({ diff --git a/services/ui-src/src/components/app/App.test.tsx b/services/ui-src/src/components/app/App.test.tsx index bf7353720..e83317559 100644 --- a/services/ui-src/src/components/app/App.test.tsx +++ b/services/ui-src/src/components/app/App.test.tsx @@ -1,15 +1,15 @@ import { render, screen } from "@testing-library/react"; import { act } from "react-dom/test-utils"; -import { axe } from "jest-axe"; +// components +import { App } from "components"; // utils +import { UserProvider, useStore } from "utils"; import { mockNoUserStore, RouterWrappedComponent, mockUseStore, } from "utils/testing/setupJest"; -import { UserProvider, useStore } from "utils"; -//components -import { App } from "components"; +import { testA11yAct } from "utils/testing/commonTests"; jest.mock("utils/state/useStore"); const mockedUseStore = useStore as jest.MockedFunction; @@ -23,7 +23,7 @@ const appComponent = ( ); -describe("Test App", () => { +describe("", () => { test("App is visible", async () => { await act(async () => { await render(appComponent); @@ -38,13 +38,6 @@ describe("Test App", () => { }); expect(screen.getByTestId("login-container")).toBeVisible(); }); -}); -describe("App login page accessibility", () => { - it("Should not have basic accessibility issues", async () => { - const { container } = render(appComponent); - await act(async () => { - expect(await axe(container)).toHaveNoViolations(); - }); - }); + testA11yAct(appComponent); }); diff --git a/services/ui-src/src/components/app/AppRoutes.test.tsx b/services/ui-src/src/components/app/AppRoutes.test.tsx index 41e7bbaaa..f442203d9 100644 --- a/services/ui-src/src/components/app/AppRoutes.test.tsx +++ b/services/ui-src/src/components/app/AppRoutes.test.tsx @@ -35,124 +35,130 @@ const appRoutesComponent = (history: any) => ( let history: any; const tempScroll = window.HTMLElement.prototype.scrollIntoView; -describe("Test AppRoutes for admin-specific routes", () => { - beforeEach(async () => { - window.HTMLElement.prototype.scrollIntoView = function () {}; - mockedUseStore.mockReturnValue({ - ...mockAdminUserStore, - ...mockBannerStore, +describe("", () => { + describe("Test AppRoutes for admin-specific routes", () => { + beforeEach(async () => { + window.HTMLElement.prototype.scrollIntoView = function () {}; + mockedUseStore.mockReturnValue({ + ...mockAdminUserStore, + ...mockBannerStore, + }); + history = createMemoryHistory(); + history.push("/admin"); + await act(async () => { + await render(appRoutesComponent(history)); + }); }); - history = createMemoryHistory(); - history.push("/admin"); - await act(async () => { - await render(appRoutesComponent(history)); + afterEach(async () => { + window.HTMLElement.prototype.scrollIntoView = tempScroll; }); - }); - afterEach(async () => { - window.HTMLElement.prototype.scrollIntoView = tempScroll; - }); - test("/admin is visible for admin user", async () => { - const currentPath = history.location.pathname; - expect(currentPath).toEqual("/admin"); - }); -}); - -describe("Test AppRoutes for non-admin-specific routes", () => { - beforeEach(async () => { - mockedUseStore.mockReturnValue({ - ...mockStateUserStore, - ...mockBannerStore, + test("/admin is visible for admin user", async () => { + const currentPath = history.location.pathname; + expect(currentPath).toEqual("/admin"); }); - history = createMemoryHistory(); - history.push("/admin"); - await act(async () => { - await render(appRoutesComponent(history)); - }); - }); - - test("/admin not visible for state user; redirects to /profile", async () => { - const currentPath = history.location.pathname; - expect(currentPath).toEqual("/profile"); }); -}); -describe("Test MCPAR and MLR report routes", () => { - test("MCPAR routes load correctly", async () => { - mockedUseStore.mockReturnValue({ - ...mockStateUserStore, - ...mockBannerStore, - ...mockMcparReportStore, + describe("Test AppRoutes for non-admin-specific routes", () => { + beforeEach(async () => { + mockedUseStore.mockReturnValue({ + ...mockStateUserStore, + ...mockBannerStore, + }); + history = createMemoryHistory(); + history.push("/admin"); + await act(async () => { + await render(appRoutesComponent(history)); + }); }); - history = createMemoryHistory(); - history.push("/mcpar"); - await act(async () => { - await render(appRoutesComponent(history)); + + test("/admin not visible for state user; redirects to /profile", async () => { + const currentPath = history.location.pathname; + expect(currentPath).toEqual("/profile"); }); - expect( - screen.getByText("Managed Care Program Annual Report (MCPAR)") - ).toBeVisible(); }); - test("MLR routes load correctly", async () => { - mockedUseStore.mockReturnValue({ - ...mockStateUserStore, - ...mockBannerStore, - ...mockMlrReportStore, + describe("Test MCPAR and MLR report routes", () => { + test("MCPAR routes load correctly", async () => { + mockedUseStore.mockReturnValue({ + ...mockStateUserStore, + ...mockBannerStore, + ...mockMcparReportStore, + }); + history = createMemoryHistory(); + history.push("/mcpar"); + await act(async () => { + await render(appRoutesComponent(history)); + }); + expect( + screen.getByText("Managed Care Program Annual Report (MCPAR)") + ).toBeVisible(); }); - history = createMemoryHistory(); - history.push("/mlr"); - await act(async () => { - await render(appRoutesComponent(history)); + + test("MLR routes load correctly", async () => { + mockedUseStore.mockReturnValue({ + ...mockStateUserStore, + ...mockBannerStore, + ...mockMlrReportStore, + }); + history = createMemoryHistory(); + history.push("/mlr"); + await act(async () => { + await render(appRoutesComponent(history)); + }); + expect( + screen.getByText("Medicaid Medical Loss Ratio (MLR)") + ).toBeVisible(); }); - expect(screen.getByText("Medicaid Medical Loss Ratio (MLR)")).toBeVisible(); }); -}); -describe("Test AppRoutes 404 handling", () => { - beforeEach(async () => { - mockedUseStore.mockReturnValue({ - ...mockStateUserStore, - ...mockBannerStore, + describe("Test AppRoutes 404 handling", () => { + beforeEach(async () => { + mockedUseStore.mockReturnValue({ + ...mockStateUserStore, + ...mockBannerStore, + }); + history = createMemoryHistory(); + history.push("/obviously-fake-route"); + await act(async () => { + await render(appRoutesComponent(history)); + }); }); - history = createMemoryHistory(); - history.push("/obviously-fake-route"); - await act(async () => { - await render(appRoutesComponent(history)); - }); - }); - test("not-found routes redirect to 404", () => { - expect(screen.getByText(notFoundVerbiage.header)).toBeVisible(); + test("not-found routes redirect to 404", () => { + expect(screen.getByText(notFoundVerbiage.header)).toBeVisible(); + }); }); -}); -describe("Test naaarReport feature flag functionality", () => { - beforeEach(async () => { - mockedUseStore.mockReturnValue({ - ...mockStateUserStore, - ...mockBannerStore, - ...mockNaaarReportStore, + describe("Test naaarReport feature flag functionality", () => { + beforeEach(async () => { + mockedUseStore.mockReturnValue({ + ...mockStateUserStore, + ...mockBannerStore, + ...mockNaaarReportStore, + }); }); - }); - test("if naaarReport flag is true, NAAAR routes should be accesible to users", async () => { - mockLDFlags.set({ naaarReport: true }); - history = createMemoryHistory(); - history.push("/naaar"); - await act(async () => { - await render(appRoutesComponent(history)); + test("if naaarReport flag is true, NAAAR routes should be accesible to users", async () => { + mockLDFlags.set({ naaarReport: true }); + history = createMemoryHistory(); + history.push("/naaar"); + await act(async () => { + await render(appRoutesComponent(history)); + }); + expect( + screen.getByText( + "Network Adequacy and Access Assurances Report (NAAAR)" + ) + ).toBeVisible(); }); - expect( - screen.getByText("Network Adequacy and Access Assurances Report (NAAAR)") - ).toBeVisible(); - }); - test("if naaarReport flag is false, NAAAR routes should redirect to 404 Not Found page", async () => { - mockLDFlags.set({ naaarReport: false }); - history = createMemoryHistory(); - history.push("/naaar"); - await act(async () => { - await render(appRoutesComponent(history)); + test("if naaarReport flag is false, NAAAR routes should redirect to 404 Not Found page", async () => { + mockLDFlags.set({ naaarReport: false }); + history = createMemoryHistory(); + history.push("/naaar"); + await act(async () => { + await render(appRoutesComponent(history)); + }); + expect(screen.getByText(notFoundVerbiage.header)).toBeVisible(); }); - expect(screen.getByText(notFoundVerbiage.header)).toBeVisible(); }); }); diff --git a/services/ui-src/src/components/app/Error.test.tsx b/services/ui-src/src/components/app/Error.test.tsx index c297dd6de..4cb095f20 100644 --- a/services/ui-src/src/components/app/Error.test.tsx +++ b/services/ui-src/src/components/app/Error.test.tsx @@ -1,21 +1,18 @@ import { render, screen } from "@testing-library/react"; -import { axe } from "jest-axe"; +// components import { Error } from "components"; +// utils +import { testA11y } from "utils/testing/commonTests"; +// verbiage import error from "verbiage/pages/error"; const errorView = ; -describe("Test Error view", () => { +describe("", () => { test("Check that Error page renders", () => { render(errorView); expect(screen.getByText(error.header)).toBeVisible(); }); -}); -describe("Test Error view accessibility", () => { - test("Should not have basic accessibility issues", async () => { - const { container } = render(errorView); - const results = await axe(container); - expect(results).toHaveNoViolations(); - }); + testA11y(errorView); }); diff --git a/services/ui-src/src/components/app/MainSkipNav.test.tsx b/services/ui-src/src/components/app/MainSkipNav.test.tsx index b06046072..0d53947c8 100644 --- a/services/ui-src/src/components/app/MainSkipNav.test.tsx +++ b/services/ui-src/src/components/app/MainSkipNav.test.tsx @@ -1,8 +1,10 @@ import { render, screen } from "@testing-library/react"; -import { axe } from "jest-axe"; -//components +// components import { MainSkipNav, ReportContext } from "components"; +// types import { ReportContextShape } from "types"; +// utils +import { testA11y } from "utils/testing/commonTests"; const mainSkipNavOutsideReport = ( ); -describe("Test MainSkipNav", () => { - it("should be visible and focusable", async () => { +describe("", () => { + test("should be visible and focusable", async () => { render(mainSkipNavOutsideReport); const skipNav = document.getElementById("skip-nav-main")!; skipNav.focus(); @@ -39,7 +41,7 @@ describe("Test MainSkipNav", () => { await expect(skipNavLink).toBeVisible(); }); - it("should skip to report content when on a report page", async () => { + test("should skip to report content when on a report page", async () => { render(mainSkipNavInsideReport); const skipNav = document.getElementById("skip-nav-main")!; skipNav.focus(); @@ -48,12 +50,6 @@ describe("Test MainSkipNav", () => { await expect(skipNavLink).toHaveFocus(); await expect(skipNavLink).toBeVisible(); }); -}); -describe("Test MainSkipNav accessibility", () => { - it("Should not have basic accessibility issues", async () => { - const { container } = render(mainSkipNavOutsideReport); - const results = await axe(container); - expect(results).toHaveNoViolations(); - }); + testA11y(mainSkipNavOutsideReport); }); diff --git a/services/ui-src/src/components/app/MainSkipNav.tsx b/services/ui-src/src/components/app/MainSkipNav.tsx index 0837416ba..a7d2c73dc 100644 --- a/services/ui-src/src/components/app/MainSkipNav.tsx +++ b/services/ui-src/src/components/app/MainSkipNav.tsx @@ -1,7 +1,6 @@ -// components -import { ReportContext } from "components/reports/ReportProvider"; import { useContext } from "react"; -import { SkipNav } from "components"; +// components +import { ReportContext, SkipNav } from "components"; /** * The app's main skip nav changes its target, if we are on a report route. diff --git a/services/ui-src/src/components/app/SkipNav.test.tsx b/services/ui-src/src/components/app/SkipNav.test.tsx index ba118c09e..9e16428a6 100644 --- a/services/ui-src/src/components/app/SkipNav.test.tsx +++ b/services/ui-src/src/components/app/SkipNav.test.tsx @@ -1,13 +1,14 @@ import { render, screen } from "@testing-library/react"; -import { axe } from "jest-axe"; -//components +// components import { SkipNav } from "components"; +// utils +import { testA11y } from "utils/testing/commonTests"; const skipNavComponent = ( ); -describe("Test SkipNav component", () => { +describe("", () => { test("SkipNav is visible and focusable", async () => { render(skipNavComponent); const skipNav = document.getElementById("skip-nav-test")!; @@ -17,12 +18,6 @@ describe("Test SkipNav component", () => { await expect(skipNavLink).toHaveFocus(); await expect(skipNavLink).toBeVisible(); }); -}); -describe("Test SkipNav accessibility", () => { - it("Should not have basic accessibility issues", async () => { - const { container } = render(skipNavComponent); - const results = await axe(container); - expect(results).toHaveNoViolations(); - }); + testA11y(skipNavComponent); }); diff --git a/services/ui-src/src/components/app/SkipNav.tsx b/services/ui-src/src/components/app/SkipNav.tsx index c74e652f7..8c5973a60 100644 --- a/services/ui-src/src/components/app/SkipNav.tsx +++ b/services/ui-src/src/components/app/SkipNav.tsx @@ -1,5 +1,6 @@ // components import { Link } from "@chakra-ui/react"; +// types import { AnyObject } from "types"; export const SkipNav = ({ id, href, text, sxOverride, ...props }: Props) => { diff --git a/services/ui-src/src/components/banners/AdminBannerProvider.test.tsx b/services/ui-src/src/components/banners/AdminBannerProvider.test.tsx index 00585f26e..f47e98511 100644 --- a/services/ui-src/src/components/banners/AdminBannerProvider.test.tsx +++ b/services/ui-src/src/components/banners/AdminBannerProvider.test.tsx @@ -7,6 +7,7 @@ import { AdminBannerContext, AdminBannerProvider } from "./AdminBannerProvider"; // utils import { useStore } from "utils"; import { mockBannerData } from "utils/testing/setupJest"; +// verbiage import { bannerErrors } from "verbiage/errors"; jest.mock("utils/api/requestMethods/banner", () => ({ @@ -38,7 +39,7 @@ const testComponent = ( ); -describe("Test AdminBannerProvider fetchAdminBanner method", () => { +describe("", () => { beforeEach(async () => { await act(async () => { await render(testComponent); @@ -48,69 +49,54 @@ describe("Test AdminBannerProvider fetchAdminBanner method", () => { afterEach(() => { jest.clearAllMocks(); }); - - test("fetchAdminBanner method is called on load", async () => { - expect(mockAPI.getBanner).toHaveBeenCalledTimes(1); - }); - - test("fetchAdminBanner method calls API getBanner method", async () => { - expect(mockAPI.getBanner).toHaveBeenCalledTimes(1); - await act(async () => { - const fetchButton = screen.getByText("Fetch"); - await userEvent.click(fetchButton); + describe("test fetch banner method", () => { + test("fetchAdminBanner method is called on load", async () => { + expect(mockAPI.getBanner).toHaveBeenCalledTimes(1); }); - // 1 call on render + 1 call on button click - await waitFor(() => expect(mockAPI.getBanner).toHaveBeenCalledTimes(2)); - }); - it("Shows error if fetchBanner throws error", async () => { - mockAPI.getBanner.mockImplementation(() => { - throw new Error(); + test("fetchAdminBanner method calls API getBanner method", async () => { + expect(mockAPI.getBanner).toHaveBeenCalledTimes(1); + await act(async () => { + const fetchButton = screen.getByText("Fetch"); + await userEvent.click(fetchButton); + }); + // 1 call on render + 1 call on button click + await waitFor(() => expect(mockAPI.getBanner).toHaveBeenCalledTimes(2)); }); - await act(async () => { - await render(testComponent); + test("Shows error if fetchBanner throws error", async () => { + mockAPI.getBanner.mockImplementation(() => { + throw new Error(); + }); + await act(async () => { + await render(testComponent); + }); + expect(useStore.getState().bannerErrorMessage).toBe( + bannerErrors.GET_BANNER_FAILED + ); }); - expect(useStore.getState().bannerErrorMessage).toBe( - bannerErrors.GET_BANNER_FAILED - ); - }); -}); - -describe("Test AdminBannerProvider deleteAdminBanner method", () => { - afterEach(() => { - jest.clearAllMocks(); }); + describe("Test AdminBannerProvider deleteAdminBanner method", () => { + test("deleteAdminBanner method calls API deleteBanner method", async () => { + await act(async () => { + const deleteButton = screen.getByText("Delete"); + await userEvent.click(deleteButton); + }); + expect(mockAPI.deleteBanner).toHaveBeenCalledTimes(1); + expect(mockAPI.deleteBanner).toHaveBeenCalledWith(mockBannerData.key); - test("deleteAdminBanner method calls API deleteBanner method", async () => { - await act(async () => { - await render(testComponent); - }); - await act(async () => { - const deleteButton = screen.getByText("Delete"); - await userEvent.click(deleteButton); + // 1 call on render + 1 call on button click + await waitFor(() => expect(mockAPI.getBanner).toHaveBeenCalledTimes(2)); }); - expect(mockAPI.deleteBanner).toHaveBeenCalledTimes(1); - expect(mockAPI.deleteBanner).toHaveBeenCalledWith(mockBannerData.key); - - // 1 call on render + 1 call on button click - await waitFor(() => expect(mockAPI.getBanner).toHaveBeenCalledTimes(2)); }); -}); -describe("Test AdminBannerProvider writeAdminBanner method", () => { - afterEach(() => { - jest.clearAllMocks(); - }); - - test("writeAdminBanner method calls API writeBanner method", async () => { - await act(async () => { - await render(testComponent); - }); - await act(async () => { - const writeButton = screen.getByText("Write"); - await userEvent.click(writeButton); + describe("Test AdminBannerProvider writeAdminBanner method", () => { + test("writeAdminBanner method calls API writeBanner method", async () => { + await act(async () => { + const writeButton = screen.getByText("Write"); + await userEvent.click(writeButton); + }); + expect(mockAPI.writeBanner).toHaveBeenCalledTimes(1); + expect(mockAPI.writeBanner).toHaveBeenCalledWith(mockBannerData); }); - expect(mockAPI.writeBanner).toHaveBeenCalledTimes(1); - expect(mockAPI.writeBanner).toHaveBeenCalledWith(mockBannerData); }); }); diff --git a/services/ui-src/src/components/banners/AdminBannerProvider.tsx b/services/ui-src/src/components/banners/AdminBannerProvider.tsx index 6c74f85f4..761d84335 100644 --- a/services/ui-src/src/components/banners/AdminBannerProvider.tsx +++ b/services/ui-src/src/components/banners/AdminBannerProvider.tsx @@ -1,9 +1,9 @@ import { createContext, ReactNode, useMemo, useEffect } from "react"; -// utils -import { AdminBannerData, AdminBannerMethods } from "types/banners"; +// constants import { bannerId } from "../../constants"; -import { bannerErrors } from "verbiage/errors"; -// api +// types +import { AdminBannerData, AdminBannerMethods } from "types/banners"; +// utils import { deleteBanner, getBanner, @@ -11,6 +11,8 @@ import { useStore, checkDateRangeStatus, } from "utils"; +// verbiage +import { bannerErrors } from "verbiage/errors"; const ADMIN_BANNER_ID = bannerId; diff --git a/services/ui-src/src/components/banners/Banner.test.tsx b/services/ui-src/src/components/banners/Banner.test.tsx index 20aa8f120..c11388fbe 100644 --- a/services/ui-src/src/components/banners/Banner.test.tsx +++ b/services/ui-src/src/components/banners/Banner.test.tsx @@ -1,9 +1,10 @@ import { render, screen } from "@testing-library/react"; -import { axe } from "jest-axe"; -//components +// components import { Banner } from "components"; // types import { AlertTypes } from "types"; +// utils +import { testA11y } from "utils/testing/commonTests"; const bannerComponent = ( ); -describe("Test Banner Item", () => { - beforeEach(() => { - render(bannerComponent); - }); - +describe("", () => { test("Banner is visible", () => { + render(bannerComponent); expect(screen.getByText("Test banner!")).toBeVisible(); expect(screen.getByText("This is for testing.")).toBeVisible(); }); -}); -describe("Test Banner accessibility", () => { - it("Should not have basic accessibility issues", async () => { - const { container } = render(bannerComponent); - const results = await axe(container); - expect(results).toHaveNoViolations(); - }); + testA11y(bannerComponent); }); diff --git a/services/ui-src/src/components/banners/PreviewBanner.test.tsx b/services/ui-src/src/components/banners/PreviewBanner.test.tsx index 84431e825..91ddad211 100644 --- a/services/ui-src/src/components/banners/PreviewBanner.test.tsx +++ b/services/ui-src/src/components/banners/PreviewBanner.test.tsx @@ -1,9 +1,10 @@ import { render, screen } from "@testing-library/react"; -import { axe } from "jest-axe"; -//components +// components import { PreviewBanner } from "components"; // types import { AlertTypes } from "types"; +// utils +import { testA11y } from "utils/testing/commonTests"; jest.mock("react-hook-form", () => ({ useFormContext: () => ({ @@ -17,21 +18,12 @@ jest.mock("react-hook-form", () => ({ const previewBannerComponent = ; -describe("Test PreviewBanner Item", () => { - beforeEach(() => { - render(previewBannerComponent); - }); - +describe("", () => { test("PreviewBanner is visible", () => { + render(previewBannerComponent); expect(screen.getByText("Mock preview banner title")).toBeVisible(); expect(screen.getByText("Mock preview banner description")).toBeVisible(); }); -}); -describe("Test PreviewBanner accessibility", () => { - it("Should not have basic accessibility issues", async () => { - const { container } = render(previewBannerComponent); - const results = await axe(container); - expect(results).toHaveNoViolations(); - }); + testA11y(previewBannerComponent); }); diff --git a/services/ui-src/src/components/cards/Card.test.tsx b/services/ui-src/src/components/cards/Card.test.tsx index eb9b0aad3..dace3640b 100644 --- a/services/ui-src/src/components/cards/Card.test.tsx +++ b/services/ui-src/src/components/cards/Card.test.tsx @@ -1,7 +1,8 @@ import { render, screen } from "@testing-library/react"; -import { axe } from "jest-axe"; -//components +// components import { Card } from "components"; +// utils +import { testA11y } from "utils/testing/commonTests"; const cardComponent = ( @@ -9,20 +10,11 @@ const cardComponent = ( ); -describe("Test Card", () => { - beforeEach(() => { - render(cardComponent); - }); - +describe("", () => { test("Card is visible", () => { + render(cardComponent); expect(screen.getByText("Mock child component")).toBeVisible(); }); -}); -describe("Test Card accessibility", () => { - it("Should not have basic accessibility issues", async () => { - const { container } = render(cardComponent); - const results = await axe(container); - expect(results).toHaveNoViolations(); - }); + testA11y(cardComponent); }); diff --git a/services/ui-src/src/components/cards/EmailCard.test.tsx b/services/ui-src/src/components/cards/EmailCard.test.tsx index fd6deabc5..a391e1b50 100644 --- a/services/ui-src/src/components/cards/EmailCard.test.tsx +++ b/services/ui-src/src/components/cards/EmailCard.test.tsx @@ -1,15 +1,17 @@ import { render, screen } from "@testing-library/react"; -import { axe } from "jest-axe"; -//components +// components import { EmailCard } from "components"; +// utils import { createEmailLink } from "utils/other/email"; +import { testA11y } from "utils/testing/commonTests"; +// verbiage import verbiage from "verbiage/pages/help"; const emailCardComponent = ( ); -describe("Test EmailCard", () => { +describe("", () => { beforeEach(() => { render(emailCardComponent); }); @@ -32,12 +34,6 @@ describe("Test EmailCard", () => { test("Email links are visible", () => { expect(screen.getByRole("link")).toBeVisible(); }); -}); -describe("Test EmailCard accessibility", () => { - it("Should not have basic accessibility issues", async () => { - const { container } = render(emailCardComponent); - const results = await axe(container); - expect(results).toHaveNoViolations(); - }); + testA11y(emailCardComponent); }); diff --git a/services/ui-src/src/components/cards/EmailCard.tsx b/services/ui-src/src/components/cards/EmailCard.tsx index dece838ac..84e1120d3 100644 --- a/services/ui-src/src/components/cards/EmailCard.tsx +++ b/services/ui-src/src/components/cards/EmailCard.tsx @@ -1,9 +1,10 @@ // components import { Flex, Image, Link, Text } from "@chakra-ui/react"; import { Card } from "components"; +// types +import { AnyObject } from "types"; // utils import { useBreakpoint } from "utils"; -import { AnyObject } from "types"; import { createEmailLink } from "utils/other/email"; // assets import spreadsheetIcon from "assets/icons/icon_spreadsheet.png"; diff --git a/services/ui-src/src/components/cards/EntityCard/EntityCard.test.tsx b/services/ui-src/src/components/cards/EntityCard/EntityCard.test.tsx index 1947260e5..a73540863 100644 --- a/services/ui-src/src/components/cards/EntityCard/EntityCard.test.tsx +++ b/services/ui-src/src/components/cards/EntityCard/EntityCard.test.tsx @@ -1,8 +1,8 @@ import { render, screen } from "@testing-library/react"; -import { axe } from "jest-axe"; import userEvent from "@testing-library/user-event"; // components import { EntityCard, EntityCardBottomSection } from "components"; +// utils import { mockModalDrawerReportPageJson, mockAccessMeasuresEntity, @@ -24,6 +24,7 @@ import { mockMcparReportStore, } from "utils/testing/setupJest"; import { useStore } from "utils"; +import { testA11y } from "utils/testing/commonTests"; const openAddEditEntityModal = jest.fn(); const openDeleteEntityModal = jest.fn(); @@ -99,165 +100,6 @@ const AccessMeasuresEntityCardPrintComponent = ( /> ); -describe("Test Completed AccessMeasures EntityCard", () => { - beforeEach(() => { - render(AccessMeasuresEntityCardComponent); - }); - - afterEach(() => { - jest.clearAllMocks(); - }); - - test("EntityCard is visible", () => { - expect(screen.getByTestId("entityCard")).toBeVisible(); - }); - - test("Clicking edit button opens the AddEditProgramModal", async () => { - const editEntityButton = screen.getByText(editEntityButtonText); - await userEvent.click(editEntityButton); - await expect(openAddEditEntityModal).toBeCalledTimes(1); - }); - - test("EntityCard opens the delete modal on remove click", async () => { - const removeButton = screen.getByTestId("delete-entity-button"); - await userEvent.click(removeButton); - expect(openDeleteEntityModal).toBeCalledTimes(1); - }); - - test("EntityCard opens the drawer on edit-details click", async () => { - const editDetailsButton = screen.getByText(editEntityDetailsButtonText); - await userEvent.click(editDetailsButton); - expect(mockOpenDrawer).toBeCalledTimes(1); - }); -}); - -describe("Test Unfinished AccessMeasures EntityCard", () => { - beforeEach(() => { - render(UnfinishedAccessMeasuresEntityCardComponent); - }); - - afterEach(() => { - jest.clearAllMocks(); - }); - - test("EntityCard is visible", () => { - expect(screen.getByTestId("entityCard")).toBeVisible(); - }); - - test("EntityCard opens the delete modal on remove click", async () => { - const removeButton = screen.getByTestId("delete-entity-button"); - await userEvent.click(removeButton); - expect(openDeleteEntityModal).toBeCalledTimes(1); - }); - - test("EntityCard opens the drawer on enter-details click", async () => { - const enterDetailsButton = screen.getByText(enterEntityDetailsButtonText); - await userEvent.click(enterDetailsButton); - expect(mockOpenDrawer).toBeCalledTimes(1); - }); -}); - -describe("Test AccessMeasures EntityCard accessibility", () => { - it("Unfinished AccessMeasures EntityCard should not have basic accessibility issues", async () => { - const { container } = render(UnfinishedAccessMeasuresEntityCardComponent); - const results = await axe(container); - expect(results).toHaveNoViolations(); - }); - - it("Completed AccessMeasures EntityCard should not have basic accessibility issues", async () => { - const { container } = render(AccessMeasuresEntityCardComponent); - const results = await axe(container); - expect(results).toHaveNoViolations(); - }); -}); - -describe("Test Completed Print Version EntityCard", () => { - beforeEach(() => { - render(AccessMeasuresEntityCardPrintComponent); - }); - - afterEach(() => { - jest.clearAllMocks(); - }); - - test("EntityCard in print version displays entity count", () => { - expect(screen.getByTestId("entities-count")).toBeVisible(); - }); - - test("EntityCard in print version displays print version status indicator", () => { - expect(screen.getByTestId("print-status-indicator")).toBeVisible(); - }); - - test("Finished EntityCard in print version displays completed ", () => { - expect(screen.getByText("Complete")).toBeVisible(); - }); -}); - -describe("Test Uncompleted Print Version EntityCard", () => { - beforeEach(() => { - render(UnfinishedAccessMeasuresEntityCardPrintComponent); - }); - - afterEach(() => { - jest.clearAllMocks(); - }); - - test("EntityCard in print version displays error", () => { - expect(screen.getByText("Error")).toBeVisible(); - }); -}); - -describe("Test EntityCard status indicators for AccessMeasures", () => { - test("Correct indicators for unfinished access measure", () => { - render(UnfinishedAccessMeasuresEntityCardComponent); - // status icon alt text should indicate incompleteness - expect(screen.queryByAltText("entity is incomplete")).toBeTruthy(); - - // Access measures do not have reporting periods, so their metadata is always complete - expect( - screen.queryByText("Mock entity missing reporting period message") - ).toBeFalsy(); - - // This message shows for entities with partial details; this entity isn't even started - expect( - screen.queryByText("Mock entity missing response message") - ).toBeFalsy(); - expect(screen.queryByText("Mock entity unfinished messsage")).toBeTruthy(); - - // There are no details yet, so they cannot be EDITed - expect( - screen.queryByText("Mock edit entity details button text") - ).toBeFalsy(); - expect( - screen.queryByText("Mock enter entity details button text") - ).toBeTruthy(); - }); - - test("Correct indicators for completed access measure", () => { - render(AccessMeasuresEntityCardComponent); - - // status icon alt text should indicate incompleteness - expect(screen.queryByAltText("entity is incomplete")).toBeFalsy(); - - expect( - screen.queryByText("Mock entity missing reporting period message") - ).toBeFalsy(); - - expect( - screen.queryByText("Mock entity missing response message") - ).toBeFalsy(); - expect(screen.queryByText("Mock entity unfinished messsage")).toBeFalsy(); - - // The details are complete but they can still be EDITed - expect( - screen.queryByText("Mock edit entity details button text") - ).toBeTruthy(); - expect( - screen.queryByText("Mock enter entity details button text") - ).toBeFalsy(); - }); -}); - // QUALITY MEASURES const UnstartedQualityMeasuresEntityCardComponent = ( @@ -329,386 +171,485 @@ const CompletedQualityMeasuresEntityCardComponent = ( /> ); -describe("Test Unstarted QualityMeasures EntityCard", () => { - beforeEach(() => { - render(UnstartedQualityMeasuresEntityCardComponent); - }); +// SANCTIONS +const UnfinishedSanctionsEntityCardComponent = ( + +); + +const SanctionsEntityCardComponent = ( + +); + +// Undefined EntityType + +const UndefinedEntityCardBottomSection = ( + +); + +describe("", () => { afterEach(() => { jest.clearAllMocks(); }); - test("EntityCard is visible", () => { - expect(screen.getByTestId("entityCard")).toBeVisible(); - }); + describe("Test Completed AccessMeasures EntityCard", () => { + beforeEach(() => { + render(AccessMeasuresEntityCardComponent); + }); + test("EntityCard is visible", () => { + expect(screen.getByTestId("entityCard")).toBeVisible(); + }); - test("EntityCard opens the delete modal on remove click", async () => { - const removeButton = screen.getByTestId("delete-entity-button"); - await userEvent.click(removeButton); - expect(openDeleteEntityModal).toBeCalledTimes(1); - }); + test("Clicking edit button opens the AddEditProgramModal", async () => { + const editEntityButton = screen.getByText(editEntityButtonText); + await userEvent.click(editEntityButton); + await expect(openAddEditEntityModal).toBeCalledTimes(1); + }); - test("EntityCard opens the drawer on enter-details click", async () => { - const enterDetailsButton = screen.getByText(enterEntityDetailsButtonText); - await userEvent.click(enterDetailsButton); - expect(mockOpenDrawer).toBeCalledTimes(1); - }); -}); + test("EntityCard opens the delete modal on remove click", async () => { + const removeButton = screen.getByTestId("delete-entity-button"); + await userEvent.click(removeButton); + expect(openDeleteEntityModal).toBeCalledTimes(1); + }); -describe("Test QualityMeasures EntityCard with missing details", () => { - beforeEach(() => { - render(QualityMeasuresEntityCardComponentMissingDetails); + test("EntityCard opens the drawer on edit-details click", async () => { + const editDetailsButton = screen.getByText(editEntityDetailsButtonText); + await userEvent.click(editDetailsButton); + expect(mockOpenDrawer).toBeCalledTimes(1); + }); }); - afterEach(() => { - jest.clearAllMocks(); - }); + describe("Test Unfinished AccessMeasures EntityCard", () => { + beforeEach(() => { + render(UnfinishedAccessMeasuresEntityCardComponent); + }); - test("EntityCard is visible", () => { - expect(screen.getByTestId("entityCard")).toBeVisible(); - }); + test("EntityCard is visible", () => { + expect(screen.getByTestId("entityCard")).toBeVisible(); + }); - test("Clicking edit button opens the AddEditProgramModal", async () => { - const editEntityButton = screen.getByText(editEntityButtonText); - await userEvent.click(editEntityButton); - await expect(openAddEditEntityModal).toBeCalledTimes(1); - }); + test("EntityCard opens the delete modal on remove click", async () => { + const removeButton = screen.getByTestId("delete-entity-button"); + await userEvent.click(removeButton); + expect(openDeleteEntityModal).toBeCalledTimes(1); + }); - test("EntityCard opens the delete modal on remove click", async () => { - const removeButton = screen.getByTestId("delete-entity-button"); - await userEvent.click(removeButton); - expect(openDeleteEntityModal).toBeCalledTimes(1); + test("EntityCard opens the drawer on enter-details click", async () => { + const enterDetailsButton = screen.getByText(enterEntityDetailsButtonText); + await userEvent.click(enterDetailsButton); + expect(mockOpenDrawer).toBeCalledTimes(1); + }); }); -}); -describe("Test completed QualityMeasures EntityCard", () => { - beforeEach(() => { - render(CompletedQualityMeasuresEntityCardComponent); + describe("Test AccessMeasures EntityCard accessibility", () => { + testA11y(UnfinishedAccessMeasuresEntityCardComponent); + testA11y(AccessMeasuresEntityCardComponent); }); - afterEach(() => { - jest.clearAllMocks(); - }); + describe("Test Completed Print Version EntityCard", () => { + beforeEach(() => { + render(AccessMeasuresEntityCardPrintComponent); + }); + test("EntityCard in print version displays entity count", () => { + expect(screen.getByTestId("entities-count")).toBeVisible(); + }); - test("EntityCard is visible", () => { - expect(screen.getByTestId("entityCard")).toBeVisible(); - }); + test("EntityCard in print version displays print version status indicator", () => { + expect(screen.getByTestId("print-status-indicator")).toBeVisible(); + }); - test("Clicking edit button opens the AddEditProgramModal", async () => { - const editEntityButton = screen.getByText(editEntityButtonText); - await userEvent.click(editEntityButton); - await expect(openAddEditEntityModal).toBeCalledTimes(1); + test("Finished EntityCard in print version displays completed ", () => { + expect(screen.getByText("Complete")).toBeVisible(); + }); }); - test("EntityCard opens the delete modal on remove click", async () => { - const removeButton = screen.getByTestId("delete-entity-button"); - await userEvent.click(removeButton); - expect(openDeleteEntityModal).toBeCalledTimes(1); + describe("Test Uncompleted Print Version EntityCard", () => { + test("EntityCard in print version displays error", () => { + render(UnfinishedAccessMeasuresEntityCardPrintComponent); + expect(screen.getByText("Error")).toBeVisible(); + }); }); -}); -describe("Test EntityCard status indicators for QualityMeasures", () => { - test("Correct indicators for quality measure which has not been started", () => { - render(UnstartedQualityMeasuresEntityCardComponent); - // status icon alt text should indicate incompleteness - expect(screen.queryByAltText("entity is incomplete")).toBeTruthy(); - - // This quality measure was just created from scratch, so it has a reporting period - expect( - screen.queryByText("Mock entity missing reporting period message") - ).toBeFalsy(); - - // This message shows for entities with partial details; this entity isn't even started - expect( - screen.queryByText("Mock entity missing response message") - ).toBeFalsy(); - expect(screen.queryByText("Mock entity unfinished messsage")).toBeTruthy(); - - // There are no details yet, so they cannot be EDITed - expect( - screen.queryByText("Mock edit entity details button text") - ).toBeFalsy(); - expect( - screen.queryByText("Mock enter entity details button text") - ).toBeTruthy(); - }); + describe("Test EntityCard status indicators for AccessMeasures", () => { + test("Correct indicators for unfinished access measure", () => { + render(UnfinishedAccessMeasuresEntityCardComponent); + // status icon alt text should indicate incompleteness + expect(screen.queryByAltText("entity is incomplete")).toBeTruthy(); + + // Access measures do not have reporting periods, so their metadata is always complete + expect( + screen.queryByText("Mock entity missing reporting period message") + ).toBeFalsy(); + + // This message shows for entities with partial details; this entity isn't even started + expect( + screen.queryByText("Mock entity missing response message") + ).toBeFalsy(); + expect( + screen.queryByText("Mock entity unfinished messsage") + ).toBeTruthy(); + + // There are no details yet, so they cannot be EDITed + expect( + screen.queryByText("Mock edit entity details button text") + ).toBeFalsy(); + expect( + screen.queryByText("Mock enter entity details button text") + ).toBeTruthy(); + }); - test("Correct indicators for quality measure without reporting period", () => { - render(QualityMeasuresEntityCardComponentMissingReportingPeriod); + test("Correct indicators for completed access measure", () => { + render(AccessMeasuresEntityCardComponent); - // status icon alt text should indicate incompleteness - expect(screen.queryByAltText("entity is incomplete")).toBeTruthy(); + // status icon alt text should indicate incompleteness + expect(screen.queryByAltText("entity is incomplete")).toBeFalsy(); - expect( - screen.queryByText("Mock entity missing reporting period message") - ).toBeTruthy(); + expect( + screen.queryByText("Mock entity missing reporting period message") + ).toBeFalsy(); - expect( - screen.queryByText("Mock entity missing response message") - ).toBeFalsy(); - expect(screen.queryByText("Mock entity unfinished messsage")).toBeFalsy(); + expect( + screen.queryByText("Mock entity missing response message") + ).toBeFalsy(); + expect(screen.queryByText("Mock entity unfinished messsage")).toBeFalsy(); - // The details are complete but they can still be EDITed - expect( - screen.queryByText("Mock edit entity details button text") - ).toBeTruthy(); - expect( - screen.queryByText("Mock enter entity details button text") - ).toBeFalsy(); + // The details are complete but they can still be EDITed + expect( + screen.queryByText("Mock edit entity details button text") + ).toBeTruthy(); + expect( + screen.queryByText("Mock enter entity details button text") + ).toBeFalsy(); + }); }); - test("Correct indicators for quality measure with neither reporting period nor details", () => { - render(QualityMeasuresEntityCardComponentMissingReportingPeriodAndDetails); - expect(screen.queryByAltText("entity is incomplete")).toBeTruthy(); - - expect( - screen.queryByText("Mock entity missing reporting period message") - ).toBeTruthy(); - - expect( - screen.queryByText("Mock entity missing response message") - ).toBeTruthy(); - expect(screen.queryByText("Mock entity unfinished messsage")).toBeFalsy(); - - expect( - screen.queryByText("Mock edit entity details button text") - ).toBeFalsy(); - expect( - screen.queryByText("Mock enter entity details button text") - ).toBeTruthy(); - }); + describe("Test Unstarted QualityMeasures EntityCard", () => { + beforeEach(() => { + render(UnstartedQualityMeasuresEntityCardComponent); + }); - test("Correct indicators for quality measures without details", () => { - render(QualityMeasuresEntityCardComponentMissingDetails); - expect(screen.queryByAltText("entity is incomplete")).toBeTruthy(); - - expect( - screen.queryByText("Mock entity missing reporting period message") - ).toBeFalsy(); - - expect( - screen.queryByText("Mock entity missing response message") - ).toBeTruthy(); - expect(screen.queryByText("Mock entity unfinished messsage")).toBeFalsy(); - - expect( - screen.queryByText("Mock edit entity details button text") - ).toBeFalsy(); - expect( - screen.queryByText("Mock enter entity details button text") - ).toBeTruthy(); - }); + test("EntityCard is visible", () => { + expect(screen.getByTestId("entityCard")).toBeVisible(); + }); - test("Correct indicators for quality measure which is complete", () => { - render(CompletedQualityMeasuresEntityCardComponent); - expect(screen.queryByAltText("entity is incomplete")).toBeFalsy(); - - expect( - screen.queryByText("Mock entity missing reporting period message") - ).toBeFalsy(); - - expect( - screen.queryByText("Mock entity missing response message") - ).toBeFalsy(); - expect(screen.queryByText("Mock entity unfinished messsage")).toBeFalsy(); - - expect( - screen.queryByText("Mock edit entity details button text") - ).toBeTruthy(); - expect( - screen.queryByText("Mock enter entity details button text") - ).toBeFalsy(); - }); -}); + test("EntityCard opens the delete modal on remove click", async () => { + const removeButton = screen.getByTestId("delete-entity-button"); + await userEvent.click(removeButton); + expect(openDeleteEntityModal).toBeCalledTimes(1); + }); -describe("Test QualityMeasures EntityCard accessibility", () => { - it("Unstarted QualityMeasures EntityCard should not have basic accessibility issues", async () => { - const { container } = render(UnstartedQualityMeasuresEntityCardComponent); - const results = await axe(container); - expect(results).toHaveNoViolations(); + test("EntityCard opens the drawer on enter-details click", async () => { + const enterDetailsButton = screen.getByText(enterEntityDetailsButtonText); + await userEvent.click(enterDetailsButton); + expect(mockOpenDrawer).toBeCalledTimes(1); + }); }); - it("Half-completed QualityMeasures EntityCard should not have basic accessibility issues", async () => { - mockedUseStore.mockReturnValue({ - ...mockMcparReportStore, + describe("Test QualityMeasures EntityCard with missing details", () => { + beforeEach(() => { + render(QualityMeasuresEntityCardComponentMissingDetails); }); - const { container } = render( - QualityMeasuresEntityCardComponentMissingDetails - ); - const results = await axe(container); - expect(results).toHaveNoViolations(); - }); - it("Completed QualityMeasures EntityCard should not have basic accessibility issues", async () => { - const { container } = render(CompletedQualityMeasuresEntityCardComponent); - const results = await axe(container); - expect(results).toHaveNoViolations(); + test("EntityCard is visible", () => { + expect(screen.getByTestId("entityCard")).toBeVisible(); + }); + + test("Clicking edit button opens the AddEditProgramModal", async () => { + const editEntityButton = screen.getByText(editEntityButtonText); + await userEvent.click(editEntityButton); + await expect(openAddEditEntityModal).toBeCalledTimes(1); + }); + + test("EntityCard opens the delete modal on remove click", async () => { + const removeButton = screen.getByTestId("delete-entity-button"); + await userEvent.click(removeButton); + expect(openDeleteEntityModal).toBeCalledTimes(1); + }); }); -}); -// SANCTIONS + describe("Test completed QualityMeasures EntityCard", () => { + beforeEach(() => { + render(CompletedQualityMeasuresEntityCardComponent); + }); -const UnfinishedSanctionsEntityCardComponent = ( - -); + test("EntityCard is visible", () => { + expect(screen.getByTestId("entityCard")).toBeVisible(); + }); -const SanctionsEntityCardComponent = ( - -); + test("Clicking edit button opens the AddEditProgramModal", async () => { + const editEntityButton = screen.getByText(editEntityButtonText); + await userEvent.click(editEntityButton); + await expect(openAddEditEntityModal).toBeCalledTimes(1); + }); -describe("Test Completed Sanctions EntityCard", () => { - beforeEach(() => { - render(SanctionsEntityCardComponent); + test("EntityCard opens the delete modal on remove click", async () => { + const removeButton = screen.getByTestId("delete-entity-button"); + await userEvent.click(removeButton); + expect(openDeleteEntityModal).toBeCalledTimes(1); + }); }); - afterEach(() => { - jest.clearAllMocks(); - }); + describe("Test EntityCard status indicators for QualityMeasures", () => { + test("Correct indicators for quality measure which has not been started", () => { + render(UnstartedQualityMeasuresEntityCardComponent); + // status icon alt text should indicate incompleteness + expect(screen.queryByAltText("entity is incomplete")).toBeTruthy(); + + // This quality measure was just created from scratch, so it has a reporting period + expect( + screen.queryByText("Mock entity missing reporting period message") + ).toBeFalsy(); + + // This message shows for entities with partial details; this entity isn't even started + expect( + screen.queryByText("Mock entity missing response message") + ).toBeFalsy(); + expect( + screen.queryByText("Mock entity unfinished messsage") + ).toBeTruthy(); + + // There are no details yet, so they cannot be EDITed + expect( + screen.queryByText("Mock edit entity details button text") + ).toBeFalsy(); + expect( + screen.queryByText("Mock enter entity details button text") + ).toBeTruthy(); + }); - test("EntityCard is visible", () => { - expect(screen.getByTestId("entityCard")).toBeVisible(); - }); + test("Correct indicators for quality measure without reporting period", () => { + render(QualityMeasuresEntityCardComponentMissingReportingPeriod); - test("Clicking edit button opens the AddEditProgramModal", async () => { - const editEntityButton = screen.getByText(editEntityButtonText); - await userEvent.click(editEntityButton); - await expect(openAddEditEntityModal).toBeCalledTimes(1); - }); + // status icon alt text should indicate incompleteness + expect(screen.queryByAltText("entity is incomplete")).toBeTruthy(); - test("EntityCard opens the delete modal on remove click", async () => { - const removeButton = screen.getByTestId("delete-entity-button"); - await userEvent.click(removeButton); - expect(openDeleteEntityModal).toBeCalledTimes(1); - }); + expect( + screen.queryByText("Mock entity missing reporting period message") + ).toBeTruthy(); - test("EntityCard opens the drawer on edit-details click", async () => { - const editDetailsButton = screen.getByText(editEntityDetailsButtonText); - await userEvent.click(editDetailsButton); - expect(mockOpenDrawer).toBeCalledTimes(1); - }); -}); + expect( + screen.queryByText("Mock entity missing response message") + ).toBeFalsy(); + expect(screen.queryByText("Mock entity unfinished messsage")).toBeFalsy(); -describe("Test Unfinished Sanctions EntityCard", () => { - beforeEach(() => { - render(UnfinishedSanctionsEntityCardComponent); - }); + // The details are complete but they can still be EDITed + expect( + screen.queryByText("Mock edit entity details button text") + ).toBeTruthy(); + expect( + screen.queryByText("Mock enter entity details button text") + ).toBeFalsy(); + }); - afterEach(() => { - jest.clearAllMocks(); - }); + test("Correct indicators for quality measure with neither reporting period nor details", () => { + render( + QualityMeasuresEntityCardComponentMissingReportingPeriodAndDetails + ); + expect(screen.queryByAltText("entity is incomplete")).toBeTruthy(); + + expect( + screen.queryByText("Mock entity missing reporting period message") + ).toBeTruthy(); + + expect( + screen.queryByText("Mock entity missing response message") + ).toBeTruthy(); + expect(screen.queryByText("Mock entity unfinished messsage")).toBeFalsy(); + + expect( + screen.queryByText("Mock edit entity details button text") + ).toBeFalsy(); + expect( + screen.queryByText("Mock enter entity details button text") + ).toBeTruthy(); + }); + + test("Correct indicators for quality measures without details", () => { + render(QualityMeasuresEntityCardComponentMissingDetails); + expect(screen.queryByAltText("entity is incomplete")).toBeTruthy(); + + expect( + screen.queryByText("Mock entity missing reporting period message") + ).toBeFalsy(); + + expect( + screen.queryByText("Mock entity missing response message") + ).toBeTruthy(); + expect(screen.queryByText("Mock entity unfinished messsage")).toBeFalsy(); + + expect( + screen.queryByText("Mock edit entity details button text") + ).toBeFalsy(); + expect( + screen.queryByText("Mock enter entity details button text") + ).toBeTruthy(); + }); - test("EntityCard is visible", () => { - expect(screen.getByTestId("entityCard")).toBeVisible(); + test("Correct indicators for quality measure which is complete", () => { + render(CompletedQualityMeasuresEntityCardComponent); + expect(screen.queryByAltText("entity is incomplete")).toBeFalsy(); + + expect( + screen.queryByText("Mock entity missing reporting period message") + ).toBeFalsy(); + + expect( + screen.queryByText("Mock entity missing response message") + ).toBeFalsy(); + expect(screen.queryByText("Mock entity unfinished messsage")).toBeFalsy(); + + expect( + screen.queryByText("Mock edit entity details button text") + ).toBeTruthy(); + expect( + screen.queryByText("Mock enter entity details button text") + ).toBeFalsy(); + }); }); - test("EntityCard opens the delete modal on remove click", async () => { - const removeButton = screen.getByTestId("delete-entity-button"); - await userEvent.click(removeButton); - expect(openDeleteEntityModal).toBeCalledTimes(1); + describe("Test QualityMeasures EntityCard accessibility", () => { + testA11y(UnstartedQualityMeasuresEntityCardComponent); + testA11y(QualityMeasuresEntityCardComponentMissingDetails, () => { + mockedUseStore.mockReturnValue({ + ...mockMcparReportStore, + }); + }); + testA11y(CompletedQualityMeasuresEntityCardComponent); }); - test("EntityCard opens the drawer on enter-details click", async () => { - const enterDetailsButton = screen.getByText(enterEntityDetailsButtonText); - await userEvent.click(enterDetailsButton); - expect(mockOpenDrawer).toBeCalledTimes(1); + describe("Test Completed Sanctions EntityCard", () => { + beforeEach(() => { + render(SanctionsEntityCardComponent); + }); + + test("EntityCard is visible", () => { + expect(screen.getByTestId("entityCard")).toBeVisible(); + }); + + test("Clicking edit button opens the AddEditProgramModal", async () => { + const editEntityButton = screen.getByText(editEntityButtonText); + await userEvent.click(editEntityButton); + await expect(openAddEditEntityModal).toBeCalledTimes(1); + }); + + test("EntityCard opens the delete modal on remove click", async () => { + const removeButton = screen.getByTestId("delete-entity-button"); + await userEvent.click(removeButton); + expect(openDeleteEntityModal).toBeCalledTimes(1); + }); + + test("EntityCard opens the drawer on edit-details click", async () => { + const editDetailsButton = screen.getByText(editEntityDetailsButtonText); + await userEvent.click(editDetailsButton); + expect(mockOpenDrawer).toBeCalledTimes(1); + }); }); -}); -describe("Test EntityCard status indicators for Sanctions", () => { - test("Correct indicators for unfinished sanction card", () => { - render(UnfinishedSanctionsEntityCardComponent); - // status icon alt text should indicate incompleteness - expect(screen.queryByAltText("entity is incomplete")).toBeTruthy(); - - // Sanctions do not have reporting periods, so their metadata is always complete - expect( - screen.queryByText("Mock entity missing reporting period message") - ).toBeFalsy(); - - // This message shows for entities with partial details; this entity isn't even started - expect( - screen.queryByText("Mock entity missing response message") - ).toBeFalsy(); - expect(screen.queryByText("Mock entity unfinished messsage")).toBeTruthy(); - - // There are no details yet, so they cannot be EDITed - expect( - screen.queryByText("Mock edit entity details button text") - ).toBeFalsy(); - expect( - screen.queryByText("Mock enter entity details button text") - ).toBeTruthy(); + describe("Test Unfinished Sanctions EntityCard", () => { + beforeEach(() => { + render(UnfinishedSanctionsEntityCardComponent); + }); + + test("EntityCard is visible", () => { + expect(screen.getByTestId("entityCard")).toBeVisible(); + }); + + test("EntityCard opens the delete modal on remove click", async () => { + const removeButton = screen.getByTestId("delete-entity-button"); + await userEvent.click(removeButton); + expect(openDeleteEntityModal).toBeCalledTimes(1); + }); + + test("EntityCard opens the drawer on enter-details click", async () => { + const enterDetailsButton = screen.getByText(enterEntityDetailsButtonText); + await userEvent.click(enterDetailsButton); + expect(mockOpenDrawer).toBeCalledTimes(1); + }); }); - test("Correct indicators for completed sanction", () => { - render(SanctionsEntityCardComponent); + describe("Test EntityCard status indicators for Sanctions", () => { + test("Correct indicators for unfinished sanction card", () => { + render(UnfinishedSanctionsEntityCardComponent); + // status icon alt text should indicate incompleteness + expect(screen.queryByAltText("entity is incomplete")).toBeTruthy(); + + // Sanctions do not have reporting periods, so their metadata is always complete + expect( + screen.queryByText("Mock entity missing reporting period message") + ).toBeFalsy(); + + // This message shows for entities with partial details; this entity isn't even started + expect( + screen.queryByText("Mock entity missing response message") + ).toBeFalsy(); + expect( + screen.queryByText("Mock entity unfinished messsage") + ).toBeTruthy(); + + // There are no details yet, so they cannot be EDITed + expect( + screen.queryByText("Mock edit entity details button text") + ).toBeFalsy(); + expect( + screen.queryByText("Mock enter entity details button text") + ).toBeTruthy(); + }); - // status icon alt text should indicate incompleteness - expect(screen.queryByAltText("entity is incomplete")).toBeFalsy(); + test("Correct indicators for completed sanction", () => { + render(SanctionsEntityCardComponent); - expect( - screen.queryByText("Mock entity missing reporting period message") - ).toBeFalsy(); + // status icon alt text should indicate incompleteness + expect(screen.queryByAltText("entity is incomplete")).toBeFalsy(); - expect( - screen.queryByText("Mock entity missing response message") - ).toBeFalsy(); - expect(screen.queryByText("Mock entity unfinished messsage")).toBeFalsy(); + expect( + screen.queryByText("Mock entity missing reporting period message") + ).toBeFalsy(); - // The details are complete but they can still be EDITed - expect( - screen.queryByText("Mock edit entity details button text") - ).toBeTruthy(); - expect( - screen.queryByText("Mock enter entity details button text") - ).toBeFalsy(); - }); -}); + expect( + screen.queryByText("Mock entity missing response message") + ).toBeFalsy(); + expect(screen.queryByText("Mock entity unfinished messsage")).toBeFalsy(); -describe("Test Sanctions EntityCard accessibility", () => { - it("Unfinished Sanctions EntityCard should not have basic accessibility issues", async () => { - const { container } = render(UnfinishedSanctionsEntityCardComponent); - const results = await axe(container); - expect(results).toHaveNoViolations(); + // The details are complete but they can still be EDITed + expect( + screen.queryByText("Mock edit entity details button text") + ).toBeTruthy(); + expect( + screen.queryByText("Mock enter entity details button text") + ).toBeFalsy(); + }); }); - it("Completed Sanctions EntityCard should not have basic accessibility issues", async () => { - const { container } = render(SanctionsEntityCardComponent); - const results = await axe(container); - expect(results).toHaveNoViolations(); + describe("Test Sanctions EntityCard accessibility", () => { + testA11y(UnfinishedSanctionsEntityCardComponent); + testA11y(SanctionsEntityCardComponent); }); -}); - -// Undefined EntityType - -const UndefinedEntityCardBottomSection = ( - -); -describe("Should return Entity Type by default", () => { - it("should return the entity type given", () => { - render(UndefinedEntityCardBottomSection); - expect(screen.queryByText("Undefined Entity Type")).toBeTruthy(); + describe("Should return Entity Type by default", () => { + test("should return the entity type given", () => { + render(UndefinedEntityCardBottomSection); + expect(screen.queryByText("Undefined Entity Type")).toBeTruthy(); + }); }); }); diff --git a/services/ui-src/src/components/cards/EntityCard/EntityCard.tsx b/services/ui-src/src/components/cards/EntityCard/EntityCard.tsx index db5456241..1234f7ac2 100644 --- a/services/ui-src/src/components/cards/EntityCard/EntityCard.tsx +++ b/services/ui-src/src/components/cards/EntityCard/EntityCard.tsx @@ -5,16 +5,17 @@ import { EntityCardTopSection, } from "components"; import { Box, Button, Image, Text } from "@chakra-ui/react"; +// styles +import { svgFilters } from "styles/theme"; // types import { AnyObject, EntityShape, ModalDrawerEntityTypes } from "types"; +// utils +import { useStore } from "utils"; // assets -import { svgFilters } from "styles/theme"; import completedIcon from "assets/icons/icon_check_circle.png"; import deleteIcon from "assets/icons/icon_cancel_x_circle.png"; import editIcon from "assets/icons/icon_edit.png"; import unfinishedIcon from "assets/icons/icon_error_circle.png"; -// utils -import { useStore } from "utils"; export const EntityCard = ({ entity, diff --git a/services/ui-src/src/components/cards/EntityCard/EntityCardBottomSection.tsx b/services/ui-src/src/components/cards/EntityCard/EntityCardBottomSection.tsx index 7e9cbb930..f7ab159b2 100644 --- a/services/ui-src/src/components/cards/EntityCard/EntityCardBottomSection.tsx +++ b/services/ui-src/src/components/cards/EntityCard/EntityCardBottomSection.tsx @@ -1,6 +1,6 @@ // components import { Box, Flex, Text } from "@chakra-ui/react"; -// utils +// types import { AnyObject, ModalDrawerEntityTypes } from "types"; export const EntityCardBottomSection = ({ diff --git a/services/ui-src/src/components/cards/EntityCard/EntityCardTopSection.test.tsx b/services/ui-src/src/components/cards/EntityCard/EntityCardTopSection.test.tsx index a3181c42f..75e229eef 100644 --- a/services/ui-src/src/components/cards/EntityCard/EntityCardTopSection.test.tsx +++ b/services/ui-src/src/components/cards/EntityCard/EntityCardTopSection.test.tsx @@ -1,4 +1,5 @@ import { render, screen } from "@testing-library/react"; +// components import { EntityCardTopSection } from "./EntityCardTopSection"; jest.mock("utils/state/useStore"); @@ -22,7 +23,7 @@ const entityCardTopSectionComponent = (entityType: string) => ( /> ); -describe("Test EntityCardTopSection renders", () => { +describe("", () => { beforeEach(() => { window.location.pathname === "/mcpar/export"; }); diff --git a/services/ui-src/src/components/cards/EntityCard/EntityCardTopSection.tsx b/services/ui-src/src/components/cards/EntityCard/EntityCardTopSection.tsx index 44dae5d82..53a0c5bf9 100644 --- a/services/ui-src/src/components/cards/EntityCard/EntityCardTopSection.tsx +++ b/services/ui-src/src/components/cards/EntityCard/EntityCardTopSection.tsx @@ -1,7 +1,7 @@ import { useState, useEffect } from "react"; // components import { Grid, GridItem, Heading, Text } from "@chakra-ui/react"; -// utils +// types import { AnyObject, ModalDrawerEntityTypes } from "types"; export const EntityCardTopSection = ({ diff --git a/services/ui-src/src/components/cards/TemplateCard.test.tsx b/services/ui-src/src/components/cards/TemplateCard.test.tsx index 110309021..d9c44105c 100644 --- a/services/ui-src/src/components/cards/TemplateCard.test.tsx +++ b/services/ui-src/src/components/cards/TemplateCard.test.tsx @@ -1,6 +1,5 @@ import { render, screen, waitFor } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; -import { axe } from "jest-axe"; import { act } from "react-dom/test-utils"; // components import { TemplateCard } from "components"; @@ -11,6 +10,7 @@ import { RouterWrappedComponent, } from "utils/testing/setupJest"; import { useStore } from "utils"; +import { testA11y } from "utils/testing/commonTests"; // verbiage import verbiage from "verbiage/pages/home"; @@ -59,106 +59,108 @@ const naaarTemplateCardComponent = ( mockLDFlags.setDefault({ naaarReport: true }); -describe("Test MCPAR TemplateCard", () => { - beforeEach(() => { - render(mcparTemplateCardComponent); - }); +describe("", () => { + describe("Test MCPAR TemplateCard", () => { + beforeEach(() => { + render(mcparTemplateCardComponent); + }); - test("MCPAR TemplateCard is visible", () => { - expect(screen.getByText(mcparTemplateVerbiage.title)).toBeVisible(); - }); + test("MCPAR TemplateCard is visible", () => { + expect(screen.getByText(mcparTemplateVerbiage.title)).toBeVisible(); + }); - test("MCPAR TemplateCard download button is visible and clickable", async () => { - const downloadButton = screen.getByText(mcparTemplateVerbiage.downloadText); - expect(downloadButton).toBeVisible(); - await act(async () => { - await userEvent.click(downloadButton); + test("MCPAR TemplateCard download button is visible and clickable", async () => { + const downloadButton = screen.getByText( + mcparTemplateVerbiage.downloadText + ); + expect(downloadButton).toBeVisible(); + await act(async () => { + await userEvent.click(downloadButton); + }); + await waitFor(() => + expect(mockGetSignedTemplateUrl).toHaveBeenCalledTimes(1) + ); }); - await waitFor(() => - expect(mockGetSignedTemplateUrl).toHaveBeenCalledTimes(1) - ); - }); - test("MCPAR TemplateCard image is visible on desktop", () => { - const imageAltText = "Spreadsheet icon"; - expect(screen.getByAltText(imageAltText)).toBeVisible(); - }); + test("MCPAR TemplateCard image is visible on desktop", () => { + const imageAltText = "Spreadsheet icon"; + expect(screen.getByAltText(imageAltText)).toBeVisible(); + }); - test("MCPAR TemplateCard link is visible on desktop", () => { - const templateCardLink = mcparTemplateVerbiage.link.text; - expect(screen.getByText(templateCardLink)).toBeVisible(); - }); + test("MCPAR TemplateCard link is visible on desktop", () => { + const templateCardLink = mcparTemplateVerbiage.link.text; + expect(screen.getByText(templateCardLink)).toBeVisible(); + }); - test("MCPAR TemplateCard navigates to next route on link click", async () => { - mockedUseStore.mockReturnValue(mockStateUserStore); - const templateCardLink = screen.getByText(mcparTemplateVerbiage.link.text)!; - await userEvent.click(templateCardLink); - const expectedRoute = mcparTemplateVerbiage.link.route; - await expect(mockUseNavigate).toHaveBeenCalledWith(expectedRoute); + test("MCPAR TemplateCard navigates to next route on link click", async () => { + mockedUseStore.mockReturnValue(mockStateUserStore); + const templateCardLink = screen.getByText( + mcparTemplateVerbiage.link.text + )!; + await userEvent.click(templateCardLink); + const expectedRoute = mcparTemplateVerbiage.link.route; + await expect(mockUseNavigate).toHaveBeenCalledWith(expectedRoute); + }); }); -}); -describe("Test MLR TemplateCard", () => { - beforeEach(() => { - render(mlrTemplateCardComponent); - }); + describe("Test MLR TemplateCard", () => { + beforeEach(() => { + render(mlrTemplateCardComponent); + }); - test("MLR TemplateCard is visible", () => { - expect(screen.getByText(mlrTemplateVerbiage.title)).toBeVisible(); - }); + test("MLR TemplateCard is visible", () => { + expect(screen.getByText(mlrTemplateVerbiage.title)).toBeVisible(); + }); - test("MLR TemplateCard download button is visible and clickable", async () => { - const downloadButton = screen.getByText(mlrTemplateVerbiage.downloadText); - expect(downloadButton).toBeVisible(); - await act(async () => { - await userEvent.click(downloadButton); + test("MLR TemplateCard download button is visible and clickable", async () => { + const downloadButton = screen.getByText(mlrTemplateVerbiage.downloadText); + expect(downloadButton).toBeVisible(); + await act(async () => { + await userEvent.click(downloadButton); + }); + await waitFor(() => expect(mockGetSignedTemplateUrl).toHaveBeenCalled()); }); - await waitFor(() => expect(mockGetSignedTemplateUrl).toHaveBeenCalled()); - }); - test("MLR TemplateCard image is visible on desktop", () => { - const imageAltText = "Spreadsheet icon"; - expect(screen.getByAltText(imageAltText)).toBeVisible(); - }); + test("MLR TemplateCard image is visible on desktop", () => { + const imageAltText = "Spreadsheet icon"; + expect(screen.getByAltText(imageAltText)).toBeVisible(); + }); - test("MLR TemplateCard link is visible on desktop", () => { - const templateCardLink = mlrTemplateVerbiage.link.text; - expect(screen.getByText(templateCardLink)).toBeVisible(); - }); + test("MLR TemplateCard link is visible on desktop", () => { + const templateCardLink = mlrTemplateVerbiage.link.text; + expect(screen.getByText(templateCardLink)).toBeVisible(); + }); - test("MLR TemplateCard navigates to next route on link click", async () => { - mockedUseStore.mockReturnValue(mockStateUserStore); - const templateCardLink = screen.getByText(mlrTemplateVerbiage.link.text)!; - await userEvent.click(templateCardLink); - const expectedRoute = mlrTemplateVerbiage.link.route; - await expect(mockUseNavigate).toHaveBeenCalledWith(expectedRoute); + test("MLR TemplateCard navigates to next route on link click", async () => { + mockedUseStore.mockReturnValue(mockStateUserStore); + const templateCardLink = screen.getByText(mlrTemplateVerbiage.link.text)!; + await userEvent.click(templateCardLink); + const expectedRoute = mlrTemplateVerbiage.link.route; + await expect(mockUseNavigate).toHaveBeenCalledWith(expectedRoute); + }); }); -}); -describe("Test naaarReport feature flag functionality", () => { - test("if naaarReport flag is true, NAAAR available verbiage should be visible", async () => { - mockLDFlags.set({ naaarReport: true }); - render(naaarTemplateCardComponent); - expect( - screen.getByText(naaarTemplateVerbiage.body.available) - ).toBeVisible(); - const enterNaaarButton = screen.getByText(naaarTemplateVerbiage.link.text); - expect(enterNaaarButton).toBeVisible(); - }); + describe("Test naaarReport feature flag functionality", () => { + test("if naaarReport flag is true, NAAAR available verbiage should be visible", async () => { + mockLDFlags.set({ naaarReport: true }); + render(naaarTemplateCardComponent); + expect( + screen.getByText(naaarTemplateVerbiage.body.available) + ).toBeVisible(); + const enterNaaarButton = screen.getByText( + naaarTemplateVerbiage.link.text + ); + expect(enterNaaarButton).toBeVisible(); + }); - test("if naaarReport flag is false, NAAAR available verbiage should not be visible", async () => { - mockLDFlags.set({ naaarReport: false }); - render(naaarTemplateCardComponent); - expect( - screen.queryByText(naaarTemplateVerbiage.link.text) - ).not.toBeInTheDocument(); + test("if naaarReport flag is false, NAAAR available verbiage should not be visible", async () => { + mockLDFlags.set({ naaarReport: false }); + render(naaarTemplateCardComponent); + expect( + screen.queryByText(naaarTemplateVerbiage.link.text) + ).not.toBeInTheDocument(); + }); }); -}); -describe("Test TemplateCard accessibility", () => { - it("Should not have basic accessibility issues", async () => { - const { container } = render(mcparTemplateCardComponent); - const results = await axe(container); - expect(results).toHaveNoViolations(); - }); + testA11y(mcparTemplateCardComponent); }); diff --git a/services/ui-src/src/components/cards/TemplateCard.tsx b/services/ui-src/src/components/cards/TemplateCard.tsx index 5e6ec047d..43f50514f 100644 --- a/services/ui-src/src/components/cards/TemplateCard.tsx +++ b/services/ui-src/src/components/cards/TemplateCard.tsx @@ -1,11 +1,12 @@ import { useFlags } from "launchdarkly-react-client-sdk"; +import { useNavigate } from "react-router-dom"; // components import { Button, Flex, Heading, Image, Text } from "@chakra-ui/react"; import { Card, TemplateCardAccordion } from "components"; +// types +import { AnyObject } from "types"; // utils -import { useNavigate } from "react-router-dom"; import { getSignedTemplateUrl, useBreakpoint } from "utils"; -import { AnyObject } from "types"; // assets import downloadIcon from "assets/icons/icon_download.png"; import nextIcon from "assets/icons/icon_next_white.png"; diff --git a/services/ui-src/src/components/drawers/Drawer.test.tsx b/services/ui-src/src/components/drawers/Drawer.test.tsx index 2aeb1b7f9..0009c3380 100644 --- a/services/ui-src/src/components/drawers/Drawer.test.tsx +++ b/services/ui-src/src/components/drawers/Drawer.test.tsx @@ -1,10 +1,11 @@ import { render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; -import { axe } from "jest-axe"; -//components +// components import { Drawer } from "components"; // constants import { closeText } from "../../constants"; +// utils +import { testA11y } from "utils/testing/commonTests"; // verbiage import { mockModalDrawerReportPageVerbiage } from "utils/testing/setupJest"; @@ -23,7 +24,7 @@ const drawerComponent = ( /> ); -describe("Test Drawer", () => { +describe("", () => { beforeEach(() => { render(drawerComponent); }); @@ -33,22 +34,12 @@ describe("Test Drawer", () => { screen.getByText(mockModalDrawerReportPageVerbiage.drawerTitle) ).toBeVisible(); }); -}); - -describe("Test Drawer fill form and close", () => { - it("Drawer can be closed with close button", async () => { - render(drawerComponent); + test("Drawer can be closed with close button", async () => { const closeButton = screen.getByText(closeText); expect(closeButton).toBeVisible(); await userEvent.click(closeButton); expect(mockOnClose).toHaveBeenCalledTimes(1); }); -}); -describe("Test Drawer accessibility", () => { - it("Should not have basic accessibility issues", async () => { - const { container } = render(drawerComponent); - const results = await axe(container); - expect(results).toHaveNoViolations(); - }); + testA11y(drawerComponent); }); diff --git a/services/ui-src/src/components/drawers/Drawer.tsx b/services/ui-src/src/components/drawers/Drawer.tsx index f0305444b..55482c5e0 100644 --- a/services/ui-src/src/components/drawers/Drawer.tsx +++ b/services/ui-src/src/components/drawers/Drawer.tsx @@ -12,8 +12,9 @@ import { } from "@chakra-ui/react"; import { CloseIcon } from "@cmsgov/design-system"; import { ReportDrawerDetails } from "components"; -// utils +// types import { AnyObject, CustomHtmlElement, EntityType } from "types"; +// utils import { makeMediaQueryClasses, parseCustomHtml } from "utils"; import { drawerReminderText } from "../../constants"; diff --git a/services/ui-src/src/components/drawers/ReportDrawer.test.tsx b/services/ui-src/src/components/drawers/ReportDrawer.test.tsx index 60b83c738..610144be3 100644 --- a/services/ui-src/src/components/drawers/ReportDrawer.test.tsx +++ b/services/ui-src/src/components/drawers/ReportDrawer.test.tsx @@ -1,8 +1,10 @@ import { render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; -import { axe } from "jest-axe"; -//components +// components import { ReportDrawer } from "components"; +// constants +import { closeText, saveAndCloseText } from "../../constants"; +// utils import { mockAdminUserStore, mockCompletedQualityMeasuresEntity, @@ -12,10 +14,8 @@ import { mockStateUserStore, RouterWrappedComponent, } from "utils/testing/setupJest"; -// utils import { useStore } from "utils"; -// constants -import { closeText, saveAndCloseText } from "../../constants"; +import { testA11y } from "utils/testing/commonTests"; const mockOnClose = jest.fn(); const mockOnSubmit = jest.fn(); @@ -40,23 +40,6 @@ const drawerComponent = ( ); -describe("Test ReportDrawer rendering", () => { - afterEach(() => { - jest.clearAllMocks(); - }); - it("Should render save text for state user", async () => { - mockedUseStore.mockReturnValue(mockStateUserStore); - render(drawerComponent); - expect(screen.getByText(saveAndCloseText)).toBeVisible(); - }); - - it("Should not render save text for admin user", async () => { - mockedUseStore.mockReturnValue(mockAdminUserStore); - render(drawerComponent); - expect(screen.queryByText(saveAndCloseText)).not.toBeInTheDocument(); - }); -}); - const drawerComponentWithoutFormFields = ( ); -describe("Test ReportDrawerWithoutFormFields rendering", () => { +describe("", () => { afterEach(() => { jest.clearAllMocks(); }); - it("Should render save text for state user", async () => { - mockedUseStore.mockReturnValue(mockStateUserStore); - render(drawerComponentWithoutFormFields); - expect( - screen.getByText(mockModalDrawerReportPageVerbiage.drawerNoFormMessage) - ).toBeVisible(); - }); -}); + describe("Test ReportDrawer rendering", () => { + test("Should render save text for state user", async () => { + mockedUseStore.mockReturnValue(mockStateUserStore); + render(drawerComponent); + expect(screen.getByText(saveAndCloseText)).toBeVisible(); + }); -describe("Test ReportDrawer fill form and close", () => { - beforeEach(() => { - mockedUseStore.mockReturnValue(mockStateUserStore); - render(drawerComponent); - }); - afterEach(() => { - jest.clearAllMocks(); + test("Should not render save text for admin user", async () => { + mockedUseStore.mockReturnValue(mockAdminUserStore); + render(drawerComponent); + expect(screen.queryByText(saveAndCloseText)).not.toBeInTheDocument(); + }); }); - it("ReportDrawer form can be filled and saved for state user", async () => { - const testField = screen.getByRole("textbox", { - name: /mock drawer text field/i, + describe("Test ReportDrawerWithoutFormFields rendering", () => { + test("Should render save text for state user", async () => { + mockedUseStore.mockReturnValue(mockStateUserStore); + render(drawerComponentWithoutFormFields); + expect( + screen.getByText(mockModalDrawerReportPageVerbiage.drawerNoFormMessage) + ).toBeVisible(); }); - await userEvent.type(testField, "valid fill"); - const saveCloseButton = screen.getByText(saveAndCloseText); - expect(saveCloseButton).toBeVisible(); - await userEvent.click(saveCloseButton); - expect(mockOnSubmit).toHaveBeenCalledTimes(1); }); - it("ReportDrawer can be closed with close button", async () => { - const closeButton = screen.getByText(closeText); - expect(closeButton).toBeVisible(); - await userEvent.click(closeButton); - expect(mockOnClose).toHaveBeenCalledTimes(1); - }); + describe("Test ReportDrawer fill form and close", () => { + beforeEach(() => { + mockedUseStore.mockReturnValue(mockStateUserStore); + render(drawerComponent); + }); + test("ReportDrawer form can be filled and saved for state user", async () => { + const testField = screen.getByRole("textbox", { + name: /mock drawer text field/i, + }); + await userEvent.type(testField, "valid fill"); + const saveCloseButton = screen.getByText(saveAndCloseText); + expect(saveCloseButton).toBeVisible(); + await userEvent.click(saveCloseButton); + expect(mockOnSubmit).toHaveBeenCalledTimes(1); + }); + + test("ReportDrawer can be closed with close button", async () => { + const closeButton = screen.getByText(closeText); + expect(closeButton).toBeVisible(); + await userEvent.click(closeButton); + expect(mockOnClose).toHaveBeenCalledTimes(1); + }); - it("ReportDrawer can be closed with cancel button", async () => { - const cancelButton = screen.getByText("Cancel"); - expect(cancelButton).toBeVisible(); - await userEvent.click(cancelButton); - expect(mockOnClose).toHaveBeenCalledTimes(1); + test("ReportDrawer can be closed with cancel button", async () => { + const cancelButton = screen.getByText("Cancel"); + expect(cancelButton).toBeVisible(); + await userEvent.click(cancelButton); + expect(mockOnClose).toHaveBeenCalledTimes(1); + }); }); -}); -describe("Test ReportDrawer accessibility", () => { - it("Should not have basic accessibility issues", async () => { + testA11y(drawerComponent, () => { mockedUseStore.mockReturnValue(mockStateUserStore); - const { container } = render(drawerComponent); - const results = await axe(container); - expect(results).toHaveNoViolations(); - jest.clearAllMocks(); }); }); diff --git a/services/ui-src/src/components/drawers/ReportDrawer.tsx b/services/ui-src/src/components/drawers/ReportDrawer.tsx index c59267ccb..880f2e2d2 100644 --- a/services/ui-src/src/components/drawers/ReportDrawer.tsx +++ b/services/ui-src/src/components/drawers/ReportDrawer.tsx @@ -2,8 +2,8 @@ import { MouseEventHandler } from "react"; // Components import { Box, Button, Flex, Text, Spinner } from "@chakra-ui/react"; import { Drawer, Form } from "components"; -// utils -import { useStore } from "utils"; +// constants +import { closeText, saveAndCloseText } from "../../constants"; // types import { AnyObject, @@ -12,8 +12,8 @@ import { EntityShape, EntityType, } from "types"; -// constants -import { closeText, saveAndCloseText } from "../../constants"; +// utils +import { useStore } from "utils"; export const ReportDrawer = ({ entityType, diff --git a/services/ui-src/src/components/drawers/ReportDrawerDetails.test.tsx b/services/ui-src/src/components/drawers/ReportDrawerDetails.test.tsx index a60c5180f..6a03e1533 100644 --- a/services/ui-src/src/components/drawers/ReportDrawerDetails.test.tsx +++ b/services/ui-src/src/components/drawers/ReportDrawerDetails.test.tsx @@ -1,12 +1,13 @@ import { render, screen } from "@testing-library/react"; -import { axe } from "jest-axe"; -//components +// components import { ReportDrawerDetails } from "components"; +// utils import { mockUnfinishedAccessMeasuresFormattedEntityData, mockUnfinishedQualityMeasuresFormattedEntityData, mockUnfinishedSanctionsFormattedEntityData, } from "utils/testing/setupJest"; +import { testA11y } from "utils/testing/commonTests"; const ReportDrawerDetailsAccessMeasuresComponent = ( ); -describe("Test ReportDrawerDetails renders given text", () => { - it("Should render access measures text provided in drawerDetails", async () => { - render(ReportDrawerDetailsAccessMeasuresComponent); - expect( - screen.getByText(mockUnfinishedAccessMeasuresFormattedEntityData.category) - ).toBeVisible(); - }); - - it("Should render sanctions text provided in drawerDetails", async () => { - render(ReportDrawerDetailsSanctionsComponent); - expect( - screen.getByText( - mockUnfinishedSanctionsFormattedEntityData.interventionTopic - ) - ).toBeVisible(); - }); +describe("", () => { + describe("Test ReportDrawerDetails renders given text", () => { + test("Should render access measures text provided in drawerDetails", async () => { + render(ReportDrawerDetailsAccessMeasuresComponent); + expect( + screen.getByText( + mockUnfinishedAccessMeasuresFormattedEntityData.category + ) + ).toBeVisible(); + }); - it("Should render quality measures text provided in drawerDetails", async () => { - render(ReportDrawerDetailsQualityMeasuresComponent); - expect( - screen.getByText(mockUnfinishedQualityMeasuresFormattedEntityData.domain) - ).toBeVisible(); - expect( - screen.getByText(mockUnfinishedQualityMeasuresFormattedEntityData.name) - ).toBeVisible(); - }); -}); + test("Should render sanctions text provided in drawerDetails", async () => { + render(ReportDrawerDetailsSanctionsComponent); + expect( + screen.getByText( + mockUnfinishedSanctionsFormattedEntityData.interventionTopic + ) + ).toBeVisible(); + }); -describe("Test ReportDrawerDetails invalid entity type", () => { - it("Renders invalid entity type as 'entity type'", () => { - render(ReportDrawerDetailsInvalidEntityTypeComponent); - expect(screen.getByText("bssEntities")).toBeVisible(); + test("Should render quality measures text provided in drawerDetails", async () => { + render(ReportDrawerDetailsQualityMeasuresComponent); + expect( + screen.getByText( + mockUnfinishedQualityMeasuresFormattedEntityData.domain + ) + ).toBeVisible(); + expect( + screen.getByText(mockUnfinishedQualityMeasuresFormattedEntityData.name) + ).toBeVisible(); + }); }); -}); -describe("Test ReportDrawerDetails accessibility", () => { - it("AccessMeasures drawer details should not have basic accessibility issues", async () => { - const { container } = render(ReportDrawerDetailsAccessMeasuresComponent); - const results = await axe(container); - expect(results).toHaveNoViolations(); + describe("Test ReportDrawerDetails invalid entity type", () => { + test("Renders invalid entity type as 'entity type'", () => { + render(ReportDrawerDetailsInvalidEntityTypeComponent); + expect(screen.getByText("bssEntities")).toBeVisible(); + }); }); - it("Sanctions drawer details should not have basic accessibility issues", async () => { - const { container } = render(ReportDrawerDetailsSanctionsComponent); - const results = await axe(container); - expect(results).toHaveNoViolations(); - }); - - it("QualityMeasures drawer details should not have basic accessibility issues", async () => { - const { container } = render(ReportDrawerDetailsQualityMeasuresComponent); - const results = await axe(container); - expect(results).toHaveNoViolations(); - }); - - it("Invalid entity drawer details should not have basic accessibility issues", async () => { - const { container } = render(ReportDrawerDetailsInvalidEntityTypeComponent); - const results = await axe(container); - expect(results).toHaveNoViolations(); - }); + testA11y(ReportDrawerDetailsAccessMeasuresComponent); + testA11y(ReportDrawerDetailsSanctionsComponent); + testA11y(ReportDrawerDetailsQualityMeasuresComponent); + testA11y(ReportDrawerDetailsInvalidEntityTypeComponent); }); diff --git a/services/ui-src/src/components/drawers/ReportDrawerDetails.tsx b/services/ui-src/src/components/drawers/ReportDrawerDetails.tsx index 0e0166e0a..0a759b23e 100644 --- a/services/ui-src/src/components/drawers/ReportDrawerDetails.tsx +++ b/services/ui-src/src/components/drawers/ReportDrawerDetails.tsx @@ -1,5 +1,6 @@ // components import { Box, Grid, GridItem, Heading, Text } from "@chakra-ui/react"; +// types import { AnyObject, EntityType, ModalDrawerEntityTypes } from "types"; export const ReportDrawerDetails = ({ entityType, drawerDetails }: Props) => { diff --git a/services/ui-src/src/components/export/ExportedEntityDetailsOverlaySection.test.tsx b/services/ui-src/src/components/export/ExportedEntityDetailsOverlaySection.test.tsx index eddaf81cc..419baa7fb 100644 --- a/services/ui-src/src/components/export/ExportedEntityDetailsOverlaySection.test.tsx +++ b/services/ui-src/src/components/export/ExportedEntityDetailsOverlaySection.test.tsx @@ -1,5 +1,11 @@ import { render } from "@testing-library/react"; -import { axe } from "jest-axe"; +// components +import { + ExportedEntityDetailsOverlaySection, + getEntityTableComponents, + getFormSections, + renderEntityDetailTables, +} from "./ExportedEntityDetailsOverlaySection"; // types import { ModalOverlayReportPageShape, ReportType } from "types"; // utils @@ -9,13 +15,7 @@ import { mockMlrReportContext, mockModalOverlayReportPageWithOverlayJson, } from "utils/testing/setupJest"; -// components -import { - ExportedEntityDetailsOverlaySection, - getEntityTableComponents, - getFormSections, - renderEntityDetailTables, -} from "./ExportedEntityDetailsOverlaySection"; +import { testA11y } from "utils/testing/commonTests"; const exportedEntityDetailsOverlaySectionComponent = ( content: ModalOverlayReportPageShape = mockModalOverlayReportPageWithOverlayJson @@ -32,120 +32,115 @@ mockedUseStore.mockReturnValue({ ...mockMlrReportStore, }); -describe("ExportedEntityDetailsOverlaySection", () => { - test("ExportedEntityDetailsOverlaySection is visible", async () => { - const { findByTestId, findByText } = render( - exportedEntityDetailsOverlaySectionComponent() - ); - expect( - await findByTestId("exportedEntityDetailsOverlaySection") - ).toBeVisible(); - expect(await findByText("mock subsection")).toBeVisible(); - }); - test("ExportedEntityDetailsOverlaySection renders the correct number of tables", () => { - const { getAllByRole } = render( - exportedEntityDetailsOverlaySectionComponent() - ); - const tables = getAllByRole("table"); - for (const t of tables) { - expect(t).toBeVisible(); - } - expect(tables).toHaveLength(2); +describe("", () => { + describe("renders", () => { + test("ExportedEntityDetailsOverlaySection is visible", async () => { + const { findByTestId, findByText } = render( + exportedEntityDetailsOverlaySectionComponent() + ); + expect( + await findByTestId("exportedEntityDetailsOverlaySection") + ).toBeVisible(); + expect(await findByText("mock subsection")).toBeVisible(); + }); + test("ExportedEntityDetailsOverlaySection renders the correct number of tables", () => { + const { getAllByRole } = render( + exportedEntityDetailsOverlaySectionComponent() + ); + const tables = getAllByRole("table"); + for (const t of tables) { + expect(t).toBeVisible(); + } + expect(tables).toHaveLength(2); + }); }); -}); -describe("getEntityTableComponents", () => { - test("it correctly renders display data", async () => { - const results = getEntityTableComponents( - mockMlrReportContext.report.fieldData.program, - mockModalOverlayReportPageWithOverlayJson, - [mockModalOverlayReportPageWithOverlayJson.overlayForm.fields] - ); + describe("getEntityTableComponents", () => { + test("it correctly renders display data", async () => { + const results = getEntityTableComponents( + mockMlrReportContext.report.fieldData.program, + mockModalOverlayReportPageWithOverlayJson, + [mockModalOverlayReportPageWithOverlayJson.overlayForm.fields] + ); - const { findByText } = render(
{results}
); + const { findByText } = render(
{results}
); - expect(await findByText("Standalone CHIP")); - }); + expect(await findByText("Standalone CHIP")); + }); - test("it correctly renders display data with other text fields", async () => { - mockMlrReportContext.report.fieldData.program[0][ - "report_eligibilityGroup-otherText" - ] = "Other Text"; - const results = getEntityTableComponents( - mockMlrReportContext.report.fieldData.program, - mockModalOverlayReportPageWithOverlayJson, - [mockModalOverlayReportPageWithOverlayJson.overlayForm.fields] - ); + test("it correctly renders display data with other text fields", async () => { + mockMlrReportContext.report.fieldData.program[0][ + "report_eligibilityGroup-otherText" + ] = "Other Text"; + const results = getEntityTableComponents( + mockMlrReportContext.report.fieldData.program, + mockModalOverlayReportPageWithOverlayJson, + [mockModalOverlayReportPageWithOverlayJson.overlayForm.fields] + ); - const { findByText } = render(
{results}
); + const { findByText } = render(
{results}
); - expect(await findByText("Other Text")); + expect(await findByText("Other Text")); + }); }); -}); -describe("getFormSections", () => { - test("it does not error on empty arrays", () => { - const sections = getFormSections([]); - expect(sections).toHaveLength(1); - expect(sections[0]).toHaveLength(0); - }); + describe("getFormSections", () => { + test("it does not error on empty arrays", () => { + const sections = getFormSections([]); + expect(sections).toHaveLength(1); + expect(sections[0]).toHaveLength(0); + }); - test("it does not split if there is no splitting to do", () => { - const sections = getFormSections([ - { id: "a", type: "sectionHeader" }, - { id: "b", type: "checkbox" }, - ]); - expect(sections).toHaveLength(1); - expect(sections[0].map(({ id }) => id)).toEqual(["a", "b"]); - }); + test("it does not split if there is no splitting to do", () => { + const sections = getFormSections([ + { id: "a", type: "sectionHeader" }, + { id: "b", type: "checkbox" }, + ]); + expect(sections).toHaveLength(1); + expect(sections[0].map(({ id }) => id)).toEqual(["a", "b"]); + }); - test("it splits out a new subsection for each header", () => { - const sections = getFormSections([ - { id: "a", type: "sectionHeader" }, - { id: "b", type: "checkbox" }, - { id: "c", type: "checkbox" }, - { id: "d", type: "sectionHeader" }, - { id: "e", type: "sectionHeader" }, - { id: "f", type: "checkbox" }, - ]); - expect(sections).toHaveLength(3); - expect(sections[0].map(({ id }) => id)).toEqual(["a", "b", "c"]); - expect(sections[1].map(({ id }) => id)).toEqual(["d"]); - expect(sections[2].map(({ id }) => id)).toEqual(["e", "f"]); + test("it splits out a new subsection for each header", () => { + const sections = getFormSections([ + { id: "a", type: "sectionHeader" }, + { id: "b", type: "checkbox" }, + { id: "c", type: "checkbox" }, + { id: "d", type: "sectionHeader" }, + { id: "e", type: "sectionHeader" }, + { id: "f", type: "checkbox" }, + ]); + expect(sections).toHaveLength(3); + expect(sections[0].map(({ id }) => id)).toEqual(["a", "b", "c"]); + expect(sections[1].map(({ id }) => id)).toEqual(["d"]); + expect(sections[2].map(({ id }) => id)).toEqual(["e", "f"]); + }); }); -}); -describe("renderEntityDetailTables", () => { - test("it throws when using an unsupported report type", () => { - expect(() => - renderEntityDetailTables( - ReportType.NAAAR, - [], - mockModalOverlayReportPageWithOverlayJson - ) - ).toThrow(Error); - expect(() => - renderEntityDetailTables( - ReportType.MCPAR, - [], - mockModalOverlayReportPageWithOverlayJson - ) - ).toThrow(Error); - expect(() => - renderEntityDetailTables( - "Foo" as ReportType, - [], - mockModalOverlayReportPageWithOverlayJson - ) - ).toThrow(Error); + describe("renderEntityDetailTables", () => { + test("it throws when using an unsupported report type", () => { + expect(() => + renderEntityDetailTables( + ReportType.NAAAR, + [], + mockModalOverlayReportPageWithOverlayJson + ) + ).toThrow(Error); + expect(() => + renderEntityDetailTables( + ReportType.MCPAR, + [], + mockModalOverlayReportPageWithOverlayJson + ) + ).toThrow(Error); + expect(() => + renderEntityDetailTables( + "Foo" as ReportType, + [], + mockModalOverlayReportPageWithOverlayJson + ) + ).toThrow(Error); + }); }); -}); -describe("ExportedEntityDetailsOverlaySection has no accessibility issues", () => { - it("should have no violations", async () => { - const { container } = render( - exportedEntityDetailsOverlaySectionComponent() - ); - expect(await axe(container)).toHaveNoViolations(); - }); + testA11y(exportedEntityDetailsOverlaySectionComponent()); }); diff --git a/services/ui-src/src/components/export/ExportedEntityDetailsOverlaySection.tsx b/services/ui-src/src/components/export/ExportedEntityDetailsOverlaySection.tsx index c4ee90c1a..cdfac7891 100644 --- a/services/ui-src/src/components/export/ExportedEntityDetailsOverlaySection.tsx +++ b/services/ui-src/src/components/export/ExportedEntityDetailsOverlaySection.tsx @@ -14,8 +14,8 @@ import { // utils import { assertExhaustive, getEntityDetailsMLR, useStore } from "utils"; // verbiage -import mcparVerbiage from "../../verbiage/pages/mcpar/mcpar-export"; -import mlrVerbiage from "../../verbiage/pages/mlr/mlr-export"; +import mcparVerbiage from "verbiage/pages/mcpar/mcpar-export"; +import mlrVerbiage from "verbiage/pages/mlr/mlr-export"; const exportVerbiageMap: { [key in ReportType]: any } = { MCPAR: mcparVerbiage, diff --git a/services/ui-src/src/components/export/ExportedEntityDetailsTable.test.tsx b/services/ui-src/src/components/export/ExportedEntityDetailsTable.test.tsx index 2b6b4e85c..df2e460cc 100644 --- a/services/ui-src/src/components/export/ExportedEntityDetailsTable.test.tsx +++ b/services/ui-src/src/components/export/ExportedEntityDetailsTable.test.tsx @@ -1,5 +1,6 @@ import { render } from "@testing-library/react"; -import { axe } from "jest-axe"; +// components +import { ExportedEntityDetailsTable } from "components"; // utils import { mockMlrReportContext, @@ -7,8 +8,7 @@ import { mockModalOverlayReportPageWithOverlayJson, } from "utils/testing/setupJest"; import { useStore } from "utils"; -// components -import { ExportedEntityDetailsTable } from "components"; +import { testA11y } from "utils/testing/commonTests"; jest.mock("utils/state/useStore"); const mockedUseStore = useStore as jest.MockedFunction; @@ -23,8 +23,8 @@ const exportedEntityDetailsTableComponent = () => ( data-testid="exportedEntityDetailsTable" > ); -describe("ExportedEntityDetailsTable", () => { - it("renders successfully", async () => { +describe("", () => { + test("renders successfully", async () => { const { findAllByText, findByTestId } = render( exportedEntityDetailsTableComponent() ); @@ -43,11 +43,6 @@ describe("ExportedEntityDetailsTable", () => { } } }); -}); -describe("ExportedEntityDetailsTable has no accessibility issues", () => { - it("should have no violations", async () => { - const { container } = render(exportedEntityDetailsTableComponent()); - expect(await axe(container)).toHaveNoViolations(); - }); + testA11y(exportedEntityDetailsTableComponent()); }); diff --git a/services/ui-src/src/components/export/ExportedModalDrawerReportSection.test.tsx b/services/ui-src/src/components/export/ExportedModalDrawerReportSection.test.tsx index e6c15ed67..18404f09f 100644 --- a/services/ui-src/src/components/export/ExportedModalDrawerReportSection.test.tsx +++ b/services/ui-src/src/components/export/ExportedModalDrawerReportSection.test.tsx @@ -1,7 +1,8 @@ import { render, screen } from "@testing-library/react"; -import { axe } from "jest-axe"; // components import { ExportedModalDrawerReportSection } from "components"; +// types +import { ModalDrawerReportPageShape } from "types"; // utils import { mockModalDrawerReportPageJson, @@ -9,8 +10,7 @@ import { mockMcparReportStore, } from "utils/testing/setupJest"; import { useStore } from "utils"; -// types -import { ModalDrawerReportPageShape } from "types"; +import { testA11y } from "utils/testing/commonTests"; jest.mock("utils/state/useStore"); const mockedUseStore = useStore as jest.MockedFunction; @@ -22,58 +22,51 @@ const exportedReportSectionComponent = ( content: ModalDrawerReportPageShape = mockModalDrawerReportPageJson ) => ; -describe("ExportedModalDrawerReportSection renders", () => { +describe("", () => { test("ExportedModalDrawerReportSection renders", () => { const { getByTestId } = render(exportedReportSectionComponent()); const section = getByTestId("exportedModalDrawerReportSection"); expect(section).toBeVisible(); }); -}); -describe("ExportedModalDrawerReportSection displays correct verbiage if no entities are present", () => { - test("Correct message is shown if entityType is accessMeasures", () => { - mockedUseStore.mockReturnValue({ - ...mockEmptyReportStore, + describe("ExportedModalDrawerReportSection displays correct verbiage if no entities are present", () => { + test("Correct message is shown if entityType is accessMeasures", () => { + mockedUseStore.mockReturnValue({ + ...mockEmptyReportStore, + }); + render( + exportedReportSectionComponent({ + ...mockModalDrawerReportPageJson, + entityType: "accessMeasures", + }) + ); + const entityMessage = screen.getByText("0 - No access measures entered"); + expect(entityMessage).toBeVisible(); }); - render( - exportedReportSectionComponent({ - ...mockModalDrawerReportPageJson, - entityType: "accessMeasures", - }) - ); - const entityMessage = screen.getByText("0 - No access measures entered"); - expect(entityMessage).toBeVisible(); - }); - test("Correct message is shown if entityType is qualityMeasures", () => { - render( - exportedReportSectionComponent({ - ...mockModalDrawerReportPageJson, - entityType: "qualityMeasures", - }) - ); - const entityMessage = screen.getByText( - "0 - No quality & performance measures entered" - ); - expect(entityMessage).toBeVisible(); - }); - - test("Correct message is shown if entityType is sanctions", () => { - render( - exportedReportSectionComponent({ - ...mockModalDrawerReportPageJson, - entityType: "sanctions", - }) - ); - const entityMessage = screen.getByText("0 - No sanctions entered"); - expect(entityMessage).toBeVisible(); - }); -}); + test("Correct message is shown if entityType is qualityMeasures", () => { + render( + exportedReportSectionComponent({ + ...mockModalDrawerReportPageJson, + entityType: "qualityMeasures", + }) + ); + const entityMessage = screen.getByText( + "0 - No quality & performance measures entered" + ); + expect(entityMessage).toBeVisible(); + }); -describe("Test ExportedModalDrawerReportSection accessibility", () => { - it("Should not have basic accessibility issues", async () => { - const { container } = render(exportedReportSectionComponent()); - const results = await axe(container); - expect(results).toHaveNoViolations(); + test("Correct message is shown if entityType is sanctions", () => { + render( + exportedReportSectionComponent({ + ...mockModalDrawerReportPageJson, + entityType: "sanctions", + }) + ); + const entityMessage = screen.getByText("0 - No sanctions entered"); + expect(entityMessage).toBeVisible(); + }); }); + testA11y(exportedReportSectionComponent()); }); diff --git a/services/ui-src/src/components/export/ExportedModalDrawerReportSection.tsx b/services/ui-src/src/components/export/ExportedModalDrawerReportSection.tsx index 5c5346e07..a232aff29 100644 --- a/services/ui-src/src/components/export/ExportedModalDrawerReportSection.tsx +++ b/services/ui-src/src/components/export/ExportedModalDrawerReportSection.tsx @@ -1,9 +1,10 @@ // components import { Box, Text } from "@chakra-ui/react"; import { EntityCard } from "components"; +// types +import { EntityShape, ModalDrawerReportPageShape } from "types"; // utils import { getFormattedEntityData, useStore } from "utils"; -import { EntityShape, ModalDrawerReportPageShape } from "types"; // verbiage import exportVerbiage from "verbiage/pages/mcpar/mcpar-export"; diff --git a/services/ui-src/src/components/export/ExportedModalOverlayReportSection.test.tsx b/services/ui-src/src/components/export/ExportedModalOverlayReportSection.test.tsx index 2da3f1857..c4286cb6b 100644 --- a/services/ui-src/src/components/export/ExportedModalOverlayReportSection.test.tsx +++ b/services/ui-src/src/components/export/ExportedModalOverlayReportSection.test.tsx @@ -1,5 +1,9 @@ import { render, screen } from "@testing-library/react"; -import { axe } from "jest-axe"; +// components +import { + ExportedModalOverlayReportSection, + renderModalOverlayTableBody, +} from "./ExportedModalOverlayReportSection"; // types import { ModalOverlayReportPageShape, ReportType } from "types"; // utils @@ -9,13 +13,9 @@ import { mockModalOverlayReportPageJson, } from "utils/testing/setupJest"; import { useStore } from "utils"; -// components -import { - ExportedModalOverlayReportSection, - renderModalOverlayTableBody, -} from "./ExportedModalOverlayReportSection"; +import { testA11y } from "utils/testing/commonTests"; // verbiage -import mlrVerbiage from "../../verbiage/pages/mlr/mlr-export"; +import mlrVerbiage from "verbiage/pages/mlr/mlr-export"; const mockReportContext = mockMlrReportContext; const mockReportContextOther = Object.assign({}, mockReportContext); @@ -129,120 +129,113 @@ const exportedModalOverlayReportSectionComponentOther = ( /> ); -describe("Test ExportedModalOverlayReportSection", () => { +describe("", () => { test("ExportedModalOverlayReportSection renders", () => { const { getByTestId } = render(exportedModalOverlayReportSectionComponent); const section = getByTestId("exportTable"); expect(section).toBeVisible(); }); -}); -describe("Test renderModalOverlayTableBody", () => { - beforeEach(() => { - jest.clearAllMocks(); - }); - it("Should render data correctly", async () => { - mockReportContext.report.fieldData.program = [mockMlrProgram]; - const { container, findByText } = render( - exportedModalOverlayReportSectionComponent - ); - expect(await container.querySelectorAll("th").length).toEqual( - mlrTableHeader.length - ); - - // All table headers are present - expect(container.querySelectorAll("th").length).toBe(6); - - // Every entity has a row (+1 for header) - expect(container.querySelectorAll("tr").length).toBe( - mockReportContext.report.fieldData.program.length + 1 - ); - - // Check that icon is visible and has empty alt-text - const completeIcon = screen.getByRole("img"); - expect(completeIcon).toBeVisible(); - expect(completeIcon).toHaveAttribute("alt", ""); - - // Correct index - expect(await findByText("1")).toBeVisible(); - - // Correct info column - expect( - await findByText(mockMlrProgram.report_programName, { exact: false }) - ).toBeVisible(); - expect( - await findByText(mockMlrProgram.report_eligibilityGroup[0].value, { - exact: false, - }) - ).toBeVisible(); - expect( - await findByText( - `${mockMlrProgram.report_reportingPeriodStartDate} to ${mockMlrProgram.report_reportingPeriodEndDate}`, - { exact: false } - ) - ).toBeVisible(); - expect( - await findByText(mockMlrProgram.report_planName, { exact: false }) - ).toBeVisible(); - - // Correct program type - expect( - await findByText(mockMlrProgram.report_programType[0].value) - ).toBeVisible(); - - // Correct discrepancy - expect(await findByText(`N/A`)).toBeVisible(); - - // Correct notes - expect(await findByText(mockMlrProgram.report_miscellaneousNotes)); - }); - - it('Should render "other" explanations if they are filled.', async () => { - mockReportContextOther.report.fieldData.program = [mockMlrProgramOther]; - - const { findByText } = render( - exportedModalOverlayReportSectionComponentOther - ); - - expect( - await findByText( - mockMlrProgramOther["report_eligibilityGroup-otherText"], - { + describe("Test renderModalOverlayTableBody", () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + test("Should render data correctly", async () => { + mockReportContext.report.fieldData.program = [mockMlrProgram]; + const { container, findByText } = render( + exportedModalOverlayReportSectionComponent + ); + expect(await container.querySelectorAll("th").length).toEqual( + mlrTableHeader.length + ); + + // All table headers are present + expect(container.querySelectorAll("th").length).toBe(6); + + // Every entity has a row (+1 for header) + expect(container.querySelectorAll("tr").length).toBe( + mockReportContext.report.fieldData.program.length + 1 + ); + + // Check that icon is visible and has empty alt-text + const completeIcon = screen.getByRole("img"); + expect(completeIcon).toBeVisible(); + expect(completeIcon).toHaveAttribute("alt", ""); + + // Correct index + expect(await findByText("1")).toBeVisible(); + + // Correct info column + expect( + await findByText(mockMlrProgram.report_programName, { exact: false }) + ).toBeVisible(); + expect( + await findByText(mockMlrProgram.report_eligibilityGroup[0].value, { exact: false, - } - ) - ).toBeVisible(); - - expect( - await findByText( - mockMlrProgramOther["report_reportingPeriodDiscrepancyExplanation"], - { - exact: false, - } - ) - ).toBeVisible(); - }); - - it("Should render empty state with no entities.", async () => { - mockReportContextOther.report.fieldData.program = []; - const { findByText } = render( - exportedModalOverlayReportSectionComponentOther - ); - - expect(await findByText("No entities found.")).toBeVisible(); - }); - - it("Should throw an error using an unsupported report", async () => { - expect(() => renderModalOverlayTableBody(ReportType.MCPAR, [])).toThrow( - Error - ); - }); -}); - -describe("Test ExportedModalOverlayReportSection accessibility", () => { - it("Should not have basic accessibility issues", async () => { - const { container } = render(exportedModalOverlayReportSectionComponent); - const results = await axe(container); - expect(results).toHaveNoViolations(); + }) + ).toBeVisible(); + expect( + await findByText( + `${mockMlrProgram.report_reportingPeriodStartDate} to ${mockMlrProgram.report_reportingPeriodEndDate}`, + { exact: false } + ) + ).toBeVisible(); + expect( + await findByText(mockMlrProgram.report_planName, { exact: false }) + ).toBeVisible(); + + // Correct program type + expect( + await findByText(mockMlrProgram.report_programType[0].value) + ).toBeVisible(); + + // Correct discrepancy + expect(await findByText(`N/A`)).toBeVisible(); + + // Correct notes + expect(await findByText(mockMlrProgram.report_miscellaneousNotes)); + }); + + test('Should render "other" explanations if they are filled.', async () => { + mockReportContextOther.report.fieldData.program = [mockMlrProgramOther]; + + const { findByText } = render( + exportedModalOverlayReportSectionComponentOther + ); + + expect( + await findByText( + mockMlrProgramOther["report_eligibilityGroup-otherText"], + { + exact: false, + } + ) + ).toBeVisible(); + + expect( + await findByText( + mockMlrProgramOther["report_reportingPeriodDiscrepancyExplanation"], + { + exact: false, + } + ) + ).toBeVisible(); + }); + + test("Should render empty state with no entities.", async () => { + mockReportContextOther.report.fieldData.program = []; + const { findByText } = render( + exportedModalOverlayReportSectionComponentOther + ); + + expect(await findByText("No entities found.")).toBeVisible(); + }); + + test("Should throw an error using an unsupported report", async () => { + expect(() => renderModalOverlayTableBody(ReportType.MCPAR, [])).toThrow( + Error + ); + }); }); + testA11y(exportedModalOverlayReportSectionComponent); }); diff --git a/services/ui-src/src/components/export/ExportedModalOverlayReportSection.tsx b/services/ui-src/src/components/export/ExportedModalOverlayReportSection.tsx index 68ef8a20a..4dc8278d5 100644 --- a/services/ui-src/src/components/export/ExportedModalOverlayReportSection.tsx +++ b/services/ui-src/src/components/export/ExportedModalOverlayReportSection.tsx @@ -6,8 +6,8 @@ import { EntityShape, ModalOverlayReportPageShape, ReportType } from "types"; // utils import { assertExhaustive, getEntityDetailsMLR, useStore } from "utils"; // verbiage -import mcparVerbiage from "../../verbiage/pages/mcpar/mcpar-export"; -import mlrVerbiage from "../../verbiage/pages/mlr/mlr-export"; +import mcparVerbiage from "verbiage/pages/mcpar/mcpar-export"; +import mlrVerbiage from "verbiage/pages/mlr/mlr-export"; // assets import unfinishedIcon from "assets/icons/icon_error_circle_bright.png"; import finishedIcon from "assets/icons/icon_check_circle.png"; diff --git a/services/ui-src/src/components/export/ExportedReportBanner.test.tsx b/services/ui-src/src/components/export/ExportedReportBanner.test.tsx index 3b76b69f2..35179771b 100644 --- a/services/ui-src/src/components/export/ExportedReportBanner.test.tsx +++ b/services/ui-src/src/components/export/ExportedReportBanner.test.tsx @@ -1,15 +1,15 @@ import { render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { Error } from "components/app/Error"; -import { axe } from "jest-axe"; +// components +import { ExportedReportBanner } from "./ExportedReportBanner"; // utils import { useStore } from "utils"; import { mockMcparReportStore, mockMlrReportStore, } from "utils/testing/setupJest"; -// components -import { ExportedReportBanner } from "./ExportedReportBanner"; +import { testA11y } from "utils/testing/commonTests"; let mockPrint: any; @@ -20,7 +20,7 @@ const errorComponent = ; const reportBanner = ; -describe("ExportedReportBanner", () => { +describe("", () => { // temporarily mock window.print for the testing environment beforeEach(() => { mockPrint = window.print; @@ -79,15 +79,10 @@ describe("ExportedReportBanner", () => { const printButton = screen.queryByText("Download PDF"); expect(printButton).toBeNull(); }); -}); -describe("Test ExportedReportBanner accessibility", () => { - test("Should not have basic accessibility issues", async () => { + testA11y(reportBanner, () => { mockedUseStore.mockReturnValue({ ...mockMlrReportStore, }); - const { container } = render(reportBanner); - const results = await axe(container); - expect(results).toHaveNoViolations(); }); }); diff --git a/services/ui-src/src/components/export/ExportedReportBanner.tsx b/services/ui-src/src/components/export/ExportedReportBanner.tsx index 91f3a3ea2..e712218dc 100644 --- a/services/ui-src/src/components/export/ExportedReportBanner.tsx +++ b/services/ui-src/src/components/export/ExportedReportBanner.tsx @@ -1,14 +1,14 @@ -// assets -import pdfIcon from "assets/icons/icon_pdf_white.png"; // components import { Box, Button, Image, Spinner, Text } from "@chakra-ui/react"; +// types +import { ReportRoute, ReportType } from "types"; +// utils +import { useStore } from "utils"; // verbiage import mcparVerbiage from "verbiage/pages/mcpar/mcpar-export"; import mlrVerbiage from "verbiage/pages/mlr/mlr-export"; -// utils -import { useStore } from "utils"; -// types -import { ReportRoute, ReportType } from "types"; +// assets +import pdfIcon from "assets/icons/icon_pdf_white.png"; export const ExportedReportBanner = () => { const { report } = useStore(); diff --git a/services/ui-src/src/components/export/ExportedReportFieldRow.test.tsx b/services/ui-src/src/components/export/ExportedReportFieldRow.test.tsx index 66b6fbe66..c1779f67c 100644 --- a/services/ui-src/src/components/export/ExportedReportFieldRow.test.tsx +++ b/services/ui-src/src/components/export/ExportedReportFieldRow.test.tsx @@ -1,11 +1,11 @@ import { render, screen } from "@testing-library/react"; -import { axe } from "jest-axe"; // components import { ExportedReportFieldRow } from "components"; import { Table } from "@chakra-ui/react"; // utils import { mockMcparReportStore } from "utils/testing/setupJest"; import { useStore } from "utils"; +import { testA11y } from "utils/testing/commonTests"; jest.mock("utils/state/useStore"); const mockedUseStore = useStore as jest.MockedFunction; @@ -68,7 +68,7 @@ const noHintRow = ( ); -describe("ExportedReportFieldRow", () => { +describe("", () => { test("Is present", async () => { render(exportRow); const row = screen.getByTestId("exportRow"); @@ -98,12 +98,6 @@ describe("ExportedReportFieldRow", () => { const hint = screen.queryByText(/hint/); expect(hint).not.toBeInTheDocument(); }); -}); -describe("Test ExportedReportFieldRow accessibility", () => { - it("Should not have basic accessibility issues", async () => { - const { container } = render(exportRow); - const results = await axe(container); - expect(results).toHaveNoViolations(); - }); + testA11y(exportRow); }); diff --git a/services/ui-src/src/components/export/ExportedReportFieldTable.test.tsx b/services/ui-src/src/components/export/ExportedReportFieldTable.test.tsx index 8a37392d5..6093481e0 100644 --- a/services/ui-src/src/components/export/ExportedReportFieldTable.test.tsx +++ b/services/ui-src/src/components/export/ExportedReportFieldTable.test.tsx @@ -1,5 +1,8 @@ import { render, screen } from "@testing-library/react"; -import { axe } from "jest-axe"; +// components +import { ExportedReportFieldTable } from "components"; +// types +import { DrawerReportPageShape } from "types"; // utils import { mockDrawerReportPageJson, @@ -13,10 +16,7 @@ import { mockDrawerForm, } from "utils/testing/setupJest"; import { useStore } from "utils"; -// components -import { ExportedReportFieldTable } from "components"; -// types -import { DrawerReportPageShape } from "types"; +import { testA11y } from "utils/testing/commonTests"; jest.mock("utils/state/useStore"); const mockedUseStore = useStore as jest.MockedFunction; @@ -186,7 +186,7 @@ const noHintComponent = ; const hintComponent = ; -describe("ExportedReportFieldRow", () => { +describe("", () => { test("Is present", async () => { render(exportedStandardTableComponent); const row = screen.getByTestId("exportTable"); @@ -240,12 +240,6 @@ describe("ExportedReportFieldRow", () => { const hint = screen.queryByText(/Mock Hint Text/); expect(hint).not.toBeInTheDocument(); }); -}); -describe("Test ExportedReportFieldRow accessibility", () => { - it("Should not have basic accessibility issues", async () => { - const { container } = render(exportedStandardTableComponent); - const results = await axe(container); - expect(results).toHaveNoViolations(); - }); + testA11y(exportedStandardTableComponent); }); diff --git a/services/ui-src/src/components/export/ExportedReportFieldTable.tsx b/services/ui-src/src/components/export/ExportedReportFieldTable.tsx index e26180d8b..503c492f8 100644 --- a/services/ui-src/src/components/export/ExportedReportFieldTable.tsx +++ b/services/ui-src/src/components/export/ExportedReportFieldTable.tsx @@ -1,5 +1,6 @@ import { ReactElement } from "react"; // components +import { Box } from "@chakra-ui/react"; import { ExportedReportFieldRow, Table } from "components"; // types import { @@ -15,11 +16,10 @@ import { ReportType, entityTypes, } from "types"; -// verbiage -import verbiage from "verbiage/pages/mcpar/mcpar-export"; // utils import { parseCustomHtml, useStore } from "utils"; -import { Box } from "@chakra-ui/react"; +// verbiage +import verbiage from "verbiage/pages/mcpar/mcpar-export"; export const ExportedReportFieldTable = ({ section }: Props) => { const { report } = useStore(); diff --git a/services/ui-src/src/components/export/ExportedReportMetadataTable.test.tsx b/services/ui-src/src/components/export/ExportedReportMetadataTable.test.tsx index cac30b6ad..c136e1de9 100644 --- a/services/ui-src/src/components/export/ExportedReportMetadataTable.test.tsx +++ b/services/ui-src/src/components/export/ExportedReportMetadataTable.test.tsx @@ -1,5 +1,4 @@ import { render, screen } from "@testing-library/react"; -import { axe } from "jest-axe"; // components import { ExportedReportMetadataTable, @@ -8,15 +7,16 @@ import { } from "./ExportedReportMetadataTable"; // types import { ReportShape, ReportStatus, ReportType } from "types"; -// verbaige -import mcparExportVerbiage from "../../verbiage/pages/mcpar/mcpar-export"; -import mlrExportVerbiage from "../../verbiage/pages/mlr/mlr-export"; // utils import { useStore } from "utils"; import { mockMcparReportStore, mockMlrReportStore, } from "utils/testing/setupJest"; +import { testA11y } from "utils/testing/commonTests"; +// verbiage +import mcparExportVerbiage from "verbiage/pages/mcpar/mcpar-export"; +import mlrExportVerbiage from "verbiage/pages/mlr/mlr-export"; jest.mock("utils/state/useStore"); const mockedUseStore = useStore as jest.MockedFunction; @@ -57,90 +57,84 @@ const metadataTableWithContext = (context: any) => { ); }; -describe("ExportedReportMetadataTable renders", () => { - it("Should render visibly", () => { +describe("", () => { + test("Should render visibly", () => { const { getByTestId } = render(metadataTableWithContext(mockMcparContext)); const metadataTable = getByTestId("exportedReportMetadataTable"); expect(metadataTable).toBeVisible(); }); -}); -describe("Test ExportedReportMetadataTable accessibility", () => { - it("Should not have basic accessibility issues", async () => { - const { container } = render(metadataTableWithContext(mockMcparContext)); - const results = await axe(container); - expect(results).toHaveNoViolations(); - }); -}); - -describe("ExportedReportMetadataTable displays the correct content", () => { - it("Should show the correct headers for MCPAR", () => { - render(metadataTableWithContext(mockMcparContext)); - const headerTexts = Object.values( - mcparExportVerbiage.reportPage.metadataTableHeaders - ); - for (let headerText of headerTexts) { - const headerCell = screen.getByText(headerText); - expect(headerCell).toBeVisible(); - } - }); - it("Should show the correct headers for MLR", () => { - render(metadataTableWithContext(mockMlrContext)); - const headerTexts = Object.values( - mlrExportVerbiage.reportPage.metadataTableHeaders - ); - for (let headerText of headerTexts) { - const headerCell = screen.getByText(headerText); - expect(headerCell).toBeVisible(); - } - }); + describe("ExportedReportMetadataTable displays the correct content", () => { + test("Should show the correct headers for MCPAR", () => { + render(metadataTableWithContext(mockMcparContext)); + const headerTexts = Object.values( + mcparExportVerbiage.reportPage.metadataTableHeaders + ); + for (let headerText of headerTexts) { + const headerCell = screen.getByText(headerText); + expect(headerCell).toBeVisible(); + } + }); + test("Should show the correct headers for MLR", () => { + render(metadataTableWithContext(mockMlrContext)); + const headerTexts = Object.values( + mlrExportVerbiage.reportPage.metadataTableHeaders + ); + for (let headerText of headerTexts) { + const headerCell = screen.getByText(headerText); + expect(headerCell).toBeVisible(); + } + }); - it("Should show the correct data for MCPAR", () => { - render(metadataTableWithContext(mockMcparContext)); - const cellTexts = [ - "05/05/1975", - "02/24/1975", - "Thelonious States", - "Not started", - ]; - for (let cellText of cellTexts) { - const cell = screen.getByText(cellText); - expect(cell).toBeVisible(); - } - }); + test("Should show the correct data for MCPAR", () => { + render(metadataTableWithContext(mockMcparContext)); + const cellTexts = [ + "05/05/1975", + "02/24/1975", + "Thelonious States", + "Not started", + ]; + for (let cellText of cellTexts) { + const cell = screen.getByText(cellText); + expect(cell).toBeVisible(); + } + }); - it("Should show the correct data for MLR", () => { - mockedUseStore.mockReturnValue({ - ...mockMlrReportStore, + test("Should show the correct data for MLR", () => { + mockedUseStore.mockReturnValue({ + ...mockMlrReportStore, + }); + render(metadataTableWithContext(mockMlrContext)); + const cellTexts = [ + "testProgram", + "02/24/1975", + "Thelonious States", + "Not started", + ]; + for (let cellText of cellTexts) { + const cell = screen.getByText(cellText); + expect(cell).toBeVisible(); + } }); - render(metadataTableWithContext(mockMlrContext)); - const cellTexts = [ - "testProgram", - "02/24/1975", - "Thelonious States", - "Not started", - ]; - for (let cellText of cellTexts) { - const cell = screen.getByText(cellText); - expect(cell).toBeVisible(); - } }); -}); -describe("ExportedReportMetadataTable fails gracefully when appropriate", () => { - const unknownReportType = "some new report type" as ReportType; + describe("ExportedReportMetadataTable fails gracefully when appropriate", () => { + const unknownReportType = "some new report type" as ReportType; - it("Should throw an error when rendering the header for an unknown report type", () => { - expect(() => headerRowLabels(unknownReportType, {})).toThrow(Error); - }); - it("Should throw an error when rendering the body for an unknown report type", () => { - expect(() => bodyRowContent(unknownReportType, {} as ReportShape)).toThrow( - Error - ); - }); - it("Should render no data when not given a report", () => { - expect( - bodyRowContent(unknownReportType, null as any as ReportShape) - ).toEqual([[]]); + test("Should throw an error when rendering the header for an unknown report type", () => { + expect(() => headerRowLabels(unknownReportType, {})).toThrow(Error); + }); + test("Should throw an error when rendering the body for an unknown report type", () => { + expect(() => + bodyRowContent(unknownReportType, {} as ReportShape) + ).toThrow(Error); + }); + test("Should render no data when not given a report", () => { + expect( + bodyRowContent(unknownReportType, null as any as ReportShape) + ).toEqual([[]]); + }); }); + + testA11y(metadataTableWithContext(mockMcparContext)); }); diff --git a/services/ui-src/src/components/export/ExportedReportWrapper.test.tsx b/services/ui-src/src/components/export/ExportedReportWrapper.test.tsx index 1c2e8aa69..04f72d0ab 100644 --- a/services/ui-src/src/components/export/ExportedReportWrapper.test.tsx +++ b/services/ui-src/src/components/export/ExportedReportWrapper.test.tsx @@ -1,5 +1,4 @@ import { render, screen } from "@testing-library/react"; -import { axe } from "jest-axe"; // components import { ReportContext, ExportedReportWrapper } from "components"; // utils @@ -11,6 +10,7 @@ import { mockStandardReportPageJson, mockMcparReportContext, } from "utils/testing/setupJest"; +import { testA11y } from "utils/testing/commonTests"; const exportedStandardReportWrapperComponent = ( @@ -42,7 +42,7 @@ const exportedModalDrawerReportWrapperComponent = ( ); -describe("ExportedReportWrapper rendering", () => { +describe("", () => { test("ExportedStandardReportSection renders", () => { render(exportedStandardReportWrapperComponent); expect( @@ -77,24 +77,8 @@ describe("ExportedReportWrapper rendering", () => { screen.getByTestId("exportedModalDrawerReportSection") ).toBeInTheDocument(); }); -}); - -describe("Test ExportedReportWrapper accessibility", () => { - it("ExportedStandardDrawerReportWrapper should not have basic accessibility issues", async () => { - const { container } = render(exportedStandardReportWrapperComponent); - const results = await axe(container); - expect(results).toHaveNoViolations(); - }); - it("ExportedDrawerReportWrapper should not have basic accessibility issues", async () => { - const { container } = render(exportedDrawerReportWrapperComponent); - const results = await axe(container); - expect(results).toHaveNoViolations(); - }); - - it("ExportedModalDrawerReportWrapper should not have basic accessibility issues", async () => { - const { container } = render(exportedModalDrawerReportWrapperComponent); - const results = await axe(container); - expect(results).toHaveNoViolations(); - }); + testA11y(exportedStandardReportWrapperComponent); + testA11y(exportedDrawerReportWrapperComponent); + testA11y(exportedModalDrawerReportWrapperComponent); }); diff --git a/services/ui-src/src/components/export/ExportedSectionHeading.test.tsx b/services/ui-src/src/components/export/ExportedSectionHeading.test.tsx index 411606d16..1860d2c6c 100644 --- a/services/ui-src/src/components/export/ExportedSectionHeading.test.tsx +++ b/services/ui-src/src/components/export/ExportedSectionHeading.test.tsx @@ -1,9 +1,9 @@ import { render, screen } from "@testing-library/react"; -import { axe } from "jest-axe"; // components import { ExportedSectionHeading } from "components"; // utils import { mockVerbiageIntro } from "utils/testing/setupJest"; +import { testA11y } from "utils/testing/commonTests"; const mockSectionHeading = { heading: "mock-heading", @@ -17,26 +17,17 @@ const exportedReportSectionHeadingComponent = ( ); -describe("ExportedSectionHeading renders", () => { +describe("", () => { test("ExportedSectionHeading renders", () => { const { getByTestId } = render(exportedReportSectionHeadingComponent); const sectionHeading = getByTestId("exportedSectionHeading"); expect(sectionHeading).toBeVisible(); }); -}); - -describe("ExportedSectionHeading displays correct heading", () => { test("Correct heading text is shown", () => { render(exportedReportSectionHeadingComponent); const sectionHeading = screen.getByText("mock subsection"); expect(sectionHeading).toBeVisible(); }); -}); -describe("Test ExportedSectionHeading accessibility", () => { - it("Should not have basic accessibility issues", async () => { - const { container } = render(exportedReportSectionHeadingComponent); - const results = await axe(container); - expect(results).toHaveNoViolations(); - }); + testA11y(exportedReportSectionHeadingComponent); }); diff --git a/services/ui-src/src/components/fields/CheckboxField.test.tsx b/services/ui-src/src/components/fields/CheckboxField.test.tsx index a0f5fa057..1c3fe9e5d 100644 --- a/services/ui-src/src/components/fields/CheckboxField.test.tsx +++ b/services/ui-src/src/components/fields/CheckboxField.test.tsx @@ -1,10 +1,11 @@ import { render, screen } from "@testing-library/react"; -import { axe } from "jest-axe"; -//components -import { CheckboxField } from "components"; import userEvent from "@testing-library/user-event"; import { useFormContext } from "react-hook-form"; +// components +import { CheckboxField } from "components"; +// utils import { mockChoices } from "utils/testing/setupJest"; +import { testA11y } from "utils/testing/commonTests"; const mockTrigger = jest.fn(); const mockSetValue = jest.fn(); @@ -35,7 +36,7 @@ const CheckboxFieldComponent = ( /> ); -describe("Test CheckboxField component", () => { +describe("", () => { test("CheckboxField renders as Checkbox", () => { mockGetValues(undefined); render(CheckboxFieldComponent); @@ -55,13 +56,8 @@ describe("Test CheckboxField component", () => { } ); }); -}); -describe("Test CheckboxField accessibility", () => { - it("Should not have basic accessibility issues when given checkbox", async () => { + testA11y(CheckboxFieldComponent, () => { mockGetValues(undefined); - const { container } = render(CheckboxFieldComponent); - const results = await axe(container); - expect(results).toHaveNoViolations(); }); }); diff --git a/services/ui-src/src/components/fields/CheckboxField.tsx b/services/ui-src/src/components/fields/CheckboxField.tsx index 49306b570..77382aef4 100644 --- a/services/ui-src/src/components/fields/CheckboxField.tsx +++ b/services/ui-src/src/components/fields/CheckboxField.tsx @@ -1,7 +1,7 @@ // components import { Box } from "@chakra-ui/react"; import { ChoiceListField } from "components"; -// utils +// types import { ChoiceFieldProps } from "types"; export const CheckboxField = ({ diff --git a/services/ui-src/src/components/fields/ChoiceField.test.tsx b/services/ui-src/src/components/fields/ChoiceField.test.tsx index 5e6bc8918..c9c42a45d 100644 --- a/services/ui-src/src/components/fields/ChoiceField.test.tsx +++ b/services/ui-src/src/components/fields/ChoiceField.test.tsx @@ -1,9 +1,10 @@ import { render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; -import { axe } from "jest-axe"; -//components -import { ChoiceField } from "components"; import { useFormContext } from "react-hook-form"; +// components +import { ChoiceField } from "components"; +// utils +import { testA11y } from "utils/testing/commonTests"; const mockRhfMethods = { register: () => {}, @@ -26,7 +27,7 @@ const ChoiceFieldComponent = ( ); -describe("Test ChoiceField component", () => { +describe("", () => { test("ChoiceField renders as Checkbox", () => { render(ChoiceFieldComponent); const choice = screen.getByLabelText("Checkbox A"); @@ -40,41 +41,34 @@ describe("Test ChoiceField component", () => { await userEvent.click(choice); expect(choice.checked).toBe(true); }); -}); - -describe("Test ChoiceField hydration functionality", () => { - const mockFormFieldValue = true; - const mockHydrationValue = true; - const ChoiceFieldComponentWithHydrationValue = ( - - ); - test("If only formFieldValue exists, displayValue is set to it", () => { - mockGetValues(mockFormFieldValue); - render(ChoiceFieldComponent); - const choiceField: HTMLInputElement = screen.getByLabelText("Checkbox A"); - const displayValue = choiceField.value; - expect(displayValue).toBeTruthy(); - }); + describe("Test ChoiceField hydration functionality", () => { + const mockFormFieldValue = true; + const mockHydrationValue = true; + const ChoiceFieldComponentWithHydrationValue = ( + + ); - test("If only hydrationValue exists, displayValue is set to it", () => { - mockGetValues(undefined); - render(ChoiceFieldComponentWithHydrationValue); - const choiceField: HTMLInputElement = screen.getByLabelText("Checkbox B"); - const displayValue = choiceField.value; - expect(displayValue).toBeTruthy(); - }); -}); + test("If only formFieldValue exists, displayValue is set to it", () => { + mockGetValues(mockFormFieldValue); + render(ChoiceFieldComponent); + const choiceField: HTMLInputElement = screen.getByLabelText("Checkbox A"); + const displayValue = choiceField.value; + expect(displayValue).toBeTruthy(); + }); -describe("Test ChoiceField accessibility", () => { - it("Should not have basic accessibility issues", async () => { - const { container } = render(ChoiceFieldComponent); - const results = await axe(container); - expect(results).toHaveNoViolations(); + test("If only hydrationValue exists, displayValue is set to it", () => { + mockGetValues(undefined); + render(ChoiceFieldComponentWithHydrationValue); + const choiceField: HTMLInputElement = screen.getByLabelText("Checkbox B"); + const displayValue = choiceField.value; + expect(displayValue).toBeTruthy(); + }); }); + testA11y(ChoiceFieldComponent); }); diff --git a/services/ui-src/src/components/fields/ChoiceField.tsx b/services/ui-src/src/components/fields/ChoiceField.tsx index 950778f15..01439b4e7 100644 --- a/services/ui-src/src/components/fields/ChoiceField.tsx +++ b/services/ui-src/src/components/fields/ChoiceField.tsx @@ -3,8 +3,9 @@ import { useFormContext } from "react-hook-form"; // components import { Choice as CmsdsChoice } from "@cmsgov/design-system"; import { Box, Text } from "@chakra-ui/react"; -// utils +// types import { AnyObject } from "types"; +// utils import { labelTextWithOptional } from "utils"; export const ChoiceField = ({ diff --git a/services/ui-src/src/components/fields/ChoiceListField.test.tsx b/services/ui-src/src/components/fields/ChoiceListField.test.tsx index 49f60e696..00f0c0855 100644 --- a/services/ui-src/src/components/fields/ChoiceListField.test.tsx +++ b/services/ui-src/src/components/fields/ChoiceListField.test.tsx @@ -1,8 +1,9 @@ import { fireEvent, render, screen, waitFor } from "@testing-library/react"; -import { axe } from "jest-axe"; import { useFormContext } from "react-hook-form"; // components import { ChoiceListField, ReportContext } from "components"; +// types +import { ReportStatus } from "types"; // utils import { mockChoices, @@ -11,8 +12,7 @@ import { mockMcparReportStore, } from "utils/testing/setupJest"; import { useStore } from "utils"; -// types -import { ReportStatus } from "types"; +import { testA11y } from "utils/testing/commonTests"; jest.mock("utils/state/useStore"); const mockedUseStore = useStore as jest.MockedFunction; @@ -78,703 +78,708 @@ const RadioComponent = ( /> ); -describe("Test ChoiceListField component rendering", () => { - it("ChoiceList should render a normal Radiofield that doesn't have children", () => { - mockGetValues([]); - render(RadioComponent); - expect(screen.getByText("Choice 1")).toBeVisible(); - expect(screen.getByText("Choice 2")).toBeVisible(); - }); - - it("ChoiceList should render a normal Checkbox that doesn't have children", () => { - mockGetValues([]); - render(CheckboxComponent); - expect(screen.getByText("Choice 1")).toBeVisible(); - expect(screen.getByText("Choice 2")).toBeVisible(); - }); - - it("RadioField should render nested child fields for choices with children", () => { - // Render Initial State and choices - mockGetValues(undefined); - render(RadioComponentWithNestedChildren); - expect(screen.getByText("Choice 1")).toBeVisible(); - expect(screen.getByText("Choice 2")).toBeVisible(); - expect(screen.getByText("Choice 3")).toBeVisible(); - - // Choice 3 has 2 children underneath it, we can get them to show by chosing that choice - const thirdRadioOption = screen.getByLabelText("Choice 3"); - fireEvent.click(thirdRadioOption); - expect(screen.getByText("Choice 4")).toBeVisible(); - expect(screen.getByText("Choice 5")).toBeVisible(); - }); - - it("CheckboxField should render nested child fields for choices with children", async () => { - // Render Initial State and choices - render(CheckboxComponentWithNestedChildren); - expect(screen.getByText("Choice 1")).toBeVisible(); - expect(screen.getByText("Choice 2")).toBeVisible(); - expect(screen.getByText("Choice 3")).toBeVisible(); - - // Choice 3 has 2 children underneath it, we can get them to show by chosing that choice - const thirdCheckbox = screen.getByLabelText("Choice 3"); - fireEvent.click(thirdCheckbox); - expect(screen.getByText("Choice 4")).toBeVisible(); - expect(screen.getByText("Choice 5")).toBeVisible(); - }); -}); - -describe("Test Choicelist Hydration", () => { - const CheckboxHydrationComponent = ( - - - - ); +describe("", () => { + describe("Test ChoiceListField component rendering", () => { + test("ChoiceList should render a normal Radiofield that doesn't have children", () => { + mockGetValues([]); + render(RadioComponent); + expect(screen.getByText("Choice 1")).toBeVisible(); + expect(screen.getByText("Choice 2")).toBeVisible(); + }); - const CheckboxHydrationClearComponent = ( - - - - ); + test("ChoiceList should render a normal Checkbox that doesn't have children", () => { + mockGetValues([]); + render(CheckboxComponent); + expect(screen.getByText("Choice 1")).toBeVisible(); + expect(screen.getByText("Choice 2")).toBeVisible(); + }); - const RadioHydrationComponent = ( - - - - ); + test("RadioField should render nested child fields for choices with children", () => { + // Render Initial State and choices + mockGetValues(undefined); + render(RadioComponentWithNestedChildren); + expect(screen.getByText("Choice 1")).toBeVisible(); + expect(screen.getByText("Choice 2")).toBeVisible(); + expect(screen.getByText("Choice 3")).toBeVisible(); + + // Choice 3 has 2 children underneath it, we can get them to show by chosing that choice + const thirdRadioOption = screen.getByLabelText("Choice 3"); + fireEvent.click(thirdRadioOption); + expect(screen.getByText("Choice 4")).toBeVisible(); + expect(screen.getByText("Choice 5")).toBeVisible(); + }); - beforeEach(() => { - jest.clearAllMocks(); + test("CheckboxField should render nested child fields for choices with children", async () => { + // Render Initial State and choices + render(CheckboxComponentWithNestedChildren); + expect(screen.getByText("Choice 1")).toBeVisible(); + expect(screen.getByText("Choice 2")).toBeVisible(); + expect(screen.getByText("Choice 3")).toBeVisible(); + + // Choice 3 has 2 children underneath it, we can get them to show by chosing that choice + const thirdCheckbox = screen.getByLabelText("Choice 3"); + fireEvent.click(thirdCheckbox); + expect(screen.getByText("Choice 4")).toBeVisible(); + expect(screen.getByText("Choice 5")).toBeVisible(); + }); }); - test("Checkbox Choicelist correctly setting passed hydration value", () => { - /* - * Set the mock of form.GetValues to return nothing to represent that a user hasn't made any updates - * and the form should be updated based purely on the hydration values - */ - mockGetValues(undefined); - - // Create the Checkbox Component - const wrapper = render(CheckboxHydrationComponent); + describe("Test Choicelist Hydration", () => { + const CheckboxHydrationComponent = ( + + + + ); - const firstCheckbox = wrapper.getByRole("checkbox", { name: "Choice 1" }); - const secondCheckbox = wrapper.getByRole("checkbox", { name: "Choice 2" }); + const CheckboxHydrationClearComponent = ( + + + + ); - // Confirm hydration successfully made the first value checked - expect(firstCheckbox).toBeChecked(); - expect(secondCheckbox).not.toBeChecked(); - }); + const RadioHydrationComponent = ( + + + + ); - test("Checkbox Choicelist correctly setting passed field value even when given a different hydration value", () => { - /* - * Set the mock of form.GetValues to return a users choice of the first checkbox being checked - * so that even though hydration is passed as having Choice 1 as checked, the users input is respected instead - */ - mockGetValues([{ key: "Choice 2", value: "Choice 2" }]); - - // Create the Checkbox Component - const wrapper = render(CheckboxHydrationComponent); - const firstCheckbox = wrapper.getByRole("checkbox", { name: "Choice 1" }); - const secondCheckbox = wrapper.getByRole("checkbox", { name: "Choice 2" }); - - // Confirm hydration successfully made the first value checked - expect(firstCheckbox).not.toBeChecked(); - expect(secondCheckbox).toBeChecked(); - }); + beforeEach(() => { + jest.clearAllMocks(); + }); - test("Checkbox Choicelist correctly clearing nested checkbox values if clear prop is set to true", () => { - /* - * Set the mock of form.GetValues to return nothing to represent that a user hasn't made any updates - * and the form should be updated based purely on the hydration values - */ - mockGetValues(undefined); - - // Create the Checkbox Component - const wrapper = render(CheckboxHydrationClearComponent); - const firstCheckbox = wrapper.getByRole("checkbox", { name: "Choice 1" }); - const secondCheckbox = wrapper.getByRole("checkbox", { name: "Choice 2" }); - - // Confirm hydration successfully made the first value checked - expect(firstCheckbox).not.toBeChecked(); - expect(secondCheckbox).not.toBeChecked(); - }); + test("Checkbox Choicelist correctly setting passed hydration value", () => { + /* + * Set the mock of form.GetValues to return nothing to represent that a user hasn't made any updates + * and the form should be updated based purely on the hydration values + */ + mockGetValues(undefined); - // Repeat above tests for RadioField to ensure nothing changes - test("Radio Choicelist correctly setting passed hydration value", () => { - /* - * Set the mock of form.GetValues to return nothing to represent that a user hasn't made any updates - * and the form should be updated based purely on the hydration values - */ - mockGetValues(undefined); + // Create the Checkbox Component + const wrapper = render(CheckboxHydrationComponent); - // Create the Radio Component - const wrapper = render(RadioHydrationComponent); + const firstCheckbox = wrapper.getByRole("checkbox", { name: "Choice 1" }); + const secondCheckbox = wrapper.getByRole("checkbox", { + name: "Choice 2", + }); - const firstRadioOption = wrapper.getByRole("radio", { name: "Choice 1" }); - const secondRadioOption = wrapper.getByRole("radio", { name: "Choice 2" }); + // Confirm hydration successfully made the first value checked + expect(firstCheckbox).toBeChecked(); + expect(secondCheckbox).not.toBeChecked(); + }); - // Confirm hydration successfully made the first value checked - expect(firstRadioOption).toBeChecked(); - expect(secondRadioOption).not.toBeChecked(); - }); + test("Checkbox Choicelist correctly setting passed field value even when given a different hydration value", () => { + /* + * Set the mock of form.GetValues to return a users choice of the first checkbox being checked + * so that even though hydration is passed as having Choice 1 as checked, the users input is respected instead + */ + mockGetValues([{ key: "Choice 2", value: "Choice 2" }]); + + // Create the Checkbox Component + const wrapper = render(CheckboxHydrationComponent); + const firstCheckbox = wrapper.getByRole("checkbox", { name: "Choice 1" }); + const secondCheckbox = wrapper.getByRole("checkbox", { + name: "Choice 2", + }); + + // Confirm hydration successfully made the first value checked + expect(firstCheckbox).not.toBeChecked(); + expect(secondCheckbox).toBeChecked(); + }); - test("Radio Choicelist correctly setting passed field value even when given a different hydration value", () => { - /* - * Set the mock of form.GetValues to return a users choice of the first radio being checked - * so that even though hydration is passed is Choice 1 as checked, the users input is respected instead - */ - mockGetValues([{ key: "Choice 2", value: "Choice 2" }]); - - // Create the Radio Component - const wrapper = render(RadioHydrationComponent); - const firstRadioOption = wrapper.getByRole("radio", { name: "Choice 1" }); - const secondRadioOption = wrapper.getByRole("radio", { name: "Choice 2" }); - - // Confirm hydration successfully made the first value checked - expect(firstRadioOption).not.toBeChecked(); - expect(secondRadioOption).toBeChecked(); - }); -}); + test("Checkbox Choicelist correctly clearing nested checkbox values if clear prop is set to true", () => { + /* + * Set the mock of form.GetValues to return nothing to represent that a user hasn't made any updates + * and the form should be updated based purely on the hydration values + */ + mockGetValues(undefined); + + // Create the Checkbox Component + const wrapper = render(CheckboxHydrationClearComponent); + const firstCheckbox = wrapper.getByRole("checkbox", { name: "Choice 1" }); + const secondCheckbox = wrapper.getByRole("checkbox", { + name: "Choice 2", + }); + + // Confirm hydration successfully made the first value checked + expect(firstCheckbox).not.toBeChecked(); + expect(secondCheckbox).not.toBeChecked(); + }); -describe("Test Choicelist Autosaving Methods", () => { - const CheckboxWithAutosaveEnabledComponent = ( - - - - ); + // Repeat above tests for RadioField to ensure nothing changes + test("Radio Choicelist correctly setting passed hydration value", () => { + /* + * Set the mock of form.GetValues to return nothing to represent that a user hasn't made any updates + * and the form should be updated based purely on the hydration values + */ + mockGetValues(undefined); + + // Create the Radio Component + const wrapper = render(RadioHydrationComponent); + + const firstRadioOption = wrapper.getByRole("radio", { name: "Choice 1" }); + const secondRadioOption = wrapper.getByRole("radio", { + name: "Choice 2", + }); + + // Confirm hydration successfully made the first value checked + expect(firstRadioOption).toBeChecked(); + expect(secondRadioOption).not.toBeChecked(); + }); - beforeEach(() => { - jest.clearAllMocks(); + test("Radio Choicelist correctly setting passed field value even when given a different hydration value", () => { + /* + * Set the mock of form.GetValues to return a users choice of the first radio being checked + * so that even though hydration is passed is Choice 1 as checked, the users input is respected instead + */ + mockGetValues([{ key: "Choice 2", value: "Choice 2" }]); + + // Create the Radio Component + const wrapper = render(RadioHydrationComponent); + const firstRadioOption = wrapper.getByRole("radio", { name: "Choice 1" }); + const secondRadioOption = wrapper.getByRole("radio", { + name: "Choice 2", + }); + + // Confirm hydration successfully made the first value checked + expect(firstRadioOption).not.toBeChecked(); + expect(secondRadioOption).toBeChecked(); + }); }); - test("Choicelist Checkbox autosaves with checked value when autosave true, and form is valid", async () => { - mockGetValues(undefined); - - // Create the Checkbox Component - const wrapper = render(CheckboxWithAutosaveEnabledComponent); - - const firstCheckbox = wrapper.getByRole("checkbox", { name: "Choice 1" }); - const secondCheckbox = wrapper.getByRole("checkbox", { name: "Choice 2" }); - - // Select the first Checkbox and check it - expect(firstCheckbox).not.toBeChecked(); - expect(secondCheckbox).not.toBeChecked(); - fireEvent.click(firstCheckbox); - - // Confirm the checkboxes are checked correctly - const checkedCheckboxes = wrapper.getAllByRole("checkbox", { - checked: true, - }); - expect(checkedCheckboxes).toHaveLength(1); - expect(firstCheckbox).toBeChecked(); - expect(secondCheckbox).not.toBeChecked(); - - // Tab away to trigger onComponentBlur() - fireEvent.blur(firstCheckbox); - - // Make sure the form value is set to what we've clicked (Which is only Choice 1) - const firstCheckboxData = [{ key: "Choice 1", value: "Choice 1" }]; - expect(mockSetValue).toHaveBeenCalledWith( - "autosaveCheckboxField", - firstCheckboxData, - { - shouldValidate: true, - } + describe("Test Choicelist Autosaving Methods", () => { + const CheckboxWithAutosaveEnabledComponent = ( + + + ); - // Ensure we call autosave with the correct data - await waitFor(() => { - expect(mockMcparReportContext.updateReport).toHaveBeenCalledTimes(1); + beforeEach(() => { + jest.clearAllMocks(); }); - await waitFor(() => - expect(mockMcparReportContext.updateReport).toHaveBeenCalledWith( - { - reportType: mockMcparReportContext.report.reportType, - id: mockMcparReportContext.report.id, - }, + + test("Choicelist Checkbox autosaves with checked value when autosave true, and form is valid", async () => { + mockGetValues(undefined); + + // Create the Checkbox Component + const wrapper = render(CheckboxWithAutosaveEnabledComponent); + + const firstCheckbox = wrapper.getByRole("checkbox", { name: "Choice 1" }); + const secondCheckbox = wrapper.getByRole("checkbox", { + name: "Choice 2", + }); + + // Select the first Checkbox and check it + expect(firstCheckbox).not.toBeChecked(); + expect(secondCheckbox).not.toBeChecked(); + fireEvent.click(firstCheckbox); + + // Confirm the checkboxes are checked correctly + const checkedCheckboxes = wrapper.getAllByRole("checkbox", { + checked: true, + }); + expect(checkedCheckboxes).toHaveLength(1); + expect(firstCheckbox).toBeChecked(); + expect(secondCheckbox).not.toBeChecked(); + + // Tab away to trigger onComponentBlur() + fireEvent.blur(firstCheckbox); + + // Make sure the form value is set to what we've clicked (Which is only Choice 1) + const firstCheckboxData = [{ key: "Choice 1", value: "Choice 1" }]; + expect(mockSetValue).toHaveBeenCalledWith( + "autosaveCheckboxField", + firstCheckboxData, { - metadata: { - status: ReportStatus.IN_PROGRESS, - }, - fieldData: { - autosaveCheckboxField: firstCheckboxData, - }, + shouldValidate: true, } - ) - ); + ); + + // Ensure we call autosave with the correct data + await waitFor(() => { + expect(mockMcparReportContext.updateReport).toHaveBeenCalledTimes(1); + }); + await waitFor(() => + expect(mockMcparReportContext.updateReport).toHaveBeenCalledWith( + { + reportType: mockMcparReportContext.report.reportType, + id: mockMcparReportContext.report.id, + }, + { + metadata: { + status: ReportStatus.IN_PROGRESS, + }, + fieldData: { + autosaveCheckboxField: firstCheckboxData, + }, + } + ) + ); + }); }); -}); -/* - * While the onChangeHandler will be called in every other test and therefor doesn't necessarily bear repeating, - * this test focuses specifically on interaction between whats been checked in the state and whats now been unchecked. - * This is especially useful for the current interaction in how onChangeHandler sets the value for Checkboxes - */ -describe("Test Choicelist onChangeHandler", () => { - beforeEach(() => { - jest.clearAllMocks(); - }); + /* + * While the onChangeHandler will be called in every other test and therefor doesn't necessarily bear repeating, + * this test focuses specifically on interaction between whats been checked in the state and whats now been unchecked. + * This is especially useful for the current interaction in how onChangeHandler sets the value for Checkboxes + */ + describe("Test Choicelist onChangeHandler", () => { + beforeEach(() => { + jest.clearAllMocks(); + }); - test("Checking and unchecking choices in a CheckboxChoicelist are reflected correctly in the form", async () => { - mockGetValues(undefined); + test("Checking and unchecking choices in a CheckboxChoicelist are reflected correctly in the form", async () => { + mockGetValues(undefined); - // Create the Checkbox Component - const wrapper = render(CheckboxComponent); + // Create the Checkbox Component + const wrapper = render(CheckboxComponent); - const firstCheckbox = wrapper.getByRole("checkbox", { name: "Choice 1" }); - const secondCheckbox = wrapper.getByRole("checkbox", { name: "Choice 2" }); + const firstCheckbox = wrapper.getByRole("checkbox", { name: "Choice 1" }); + const secondCheckbox = wrapper.getByRole("checkbox", { + name: "Choice 2", + }); - // Make sure default state is set correctly - expect(firstCheckbox).not.toBeChecked(); - expect(secondCheckbox).not.toBeChecked(); + // Make sure default state is set correctly + expect(firstCheckbox).not.toBeChecked(); + expect(secondCheckbox).not.toBeChecked(); - // Select the first Checkbox and check it - fireEvent.click(firstCheckbox); + // Select the first Checkbox and check it + fireEvent.click(firstCheckbox); - // Confirm the checkboxes are checked correctly - const checkedCheckboxes = wrapper.getAllByRole("checkbox", { - checked: true, - }); - expect(checkedCheckboxes).toHaveLength(1); - expect(firstCheckbox).toBeChecked(); - expect(secondCheckbox).not.toBeChecked(); - - // Tab away to trigger onComponentBlur() - fireEvent.blur(firstCheckbox); - - // Make sure the form value is set to what we've clicked (Which is only Choice 1) - const firstCheckboxData = [{ key: "Choice 1", value: "Choice 1" }]; - expect(mockSetValue).toHaveBeenCalledWith( - "checkboxField", - firstCheckboxData, - { - shouldValidate: true, - } - ); + // Confirm the checkboxes are checked correctly + const checkedCheckboxes = wrapper.getAllByRole("checkbox", { + checked: true, + }); + expect(checkedCheckboxes).toHaveLength(1); + expect(firstCheckbox).toBeChecked(); + expect(secondCheckbox).not.toBeChecked(); - // Now uncheck the first checkbox to trigger the onChangeHandler - fireEvent.click(firstCheckbox); + // Tab away to trigger onComponentBlur() + fireEvent.blur(firstCheckbox); - // Confirm the checkboxes are checked correctly and reset to the default position - const uncheckedCheckboxes = wrapper.getAllByRole("checkbox", { - checked: false, + // Make sure the form value is set to what we've clicked (Which is only Choice 1) + const firstCheckboxData = [{ key: "Choice 1", value: "Choice 1" }]; + expect(mockSetValue).toHaveBeenCalledWith( + "checkboxField", + firstCheckboxData, + { + shouldValidate: true, + } + ); + + // Now uncheck the first checkbox to trigger the onChangeHandler + fireEvent.click(firstCheckbox); + + // Confirm the checkboxes are checked correctly and reset to the default position + const uncheckedCheckboxes = wrapper.getAllByRole("checkbox", { + checked: false, + }); + expect(uncheckedCheckboxes).toHaveLength(2); + expect(firstCheckbox).not.toBeChecked(); + expect(secondCheckbox).not.toBeChecked(); + + // Tab away to trigger onComponentBlur() + fireEvent.blur(firstCheckbox); + + // Make sure the form value is set to default state + expect(mockSetValue).toHaveBeenCalledWith( + "checkboxField", + firstCheckboxData, + { + shouldValidate: true, + } + ); }); - expect(uncheckedCheckboxes).toHaveLength(2); - expect(firstCheckbox).not.toBeChecked(); - expect(secondCheckbox).not.toBeChecked(); - - // Tab away to trigger onComponentBlur() - fireEvent.blur(firstCheckbox); - - // Make sure the form value is set to default state - expect(mockSetValue).toHaveBeenCalledWith( - "checkboxField", - firstCheckboxData, - { - shouldValidate: true, - } - ); - }); - test("Checking and unchecking choices in a RadioChoicelist are reflected correctly in the form", async () => { - mockGetValues(undefined); + test("Checking and unchecking choices in a RadioChoicelist are reflected correctly in the form", async () => { + mockGetValues(undefined); + + // Create the Radio Component + const wrapper = render(RadioComponent); + + const firstRadioOption = wrapper.getByRole("radio", { name: "Choice 1" }); + const secondRadioOption = wrapper.getByRole("radio", { + name: "Choice 2", + }); + + // Make sure default state is set correctly + expect(firstRadioOption).not.toBeChecked(); + expect(secondRadioOption).not.toBeChecked(); + + // Select the first Radio and check it + fireEvent.click(firstRadioOption); + + // Confirm the radio options are checked correctly + const checkedOptions = wrapper.getAllByRole("radio", { + checked: true, + }); + expect(checkedOptions).toHaveLength(1); + expect(firstRadioOption).toBeChecked(); + expect(secondRadioOption).not.toBeChecked(); + + // Tab away to trigger onComponentBlur() + fireEvent.blur(firstRadioOption); + + // Make sure the form value is set to what we've clicked (Which is only Choice 1) + const firstRadioOptionOptionData = [ + { key: "Choice 1", value: "Choice 1" }, + ]; + expect(mockSetValue).toHaveBeenCalledWith( + "radioField", + firstRadioOptionOptionData, + { + shouldValidate: true, + } + ); + + // Now check the second radio option to trigger the onChangeHandler + fireEvent.click(secondRadioOption); + + // Confirm the radio options are checked correctly + const uncheckedRadioOptions = wrapper.getAllByRole("radio", { + checked: false, + }); + expect(uncheckedRadioOptions).toHaveLength(1); + expect(firstRadioOption).not.toBeChecked(); + expect(secondRadioOption).toBeChecked(); + + // Tab away to trigger onComponentBlur() + fireEvent.blur(firstRadioOption); + + // Make sure the form value is set to default state + expect(mockSetValue).toHaveBeenCalledWith( + "radioField", + firstRadioOptionOptionData, + { + shouldValidate: true, + } + ); + }); - // Create the Radio Component - const wrapper = render(RadioComponent); + test("Checking and unchecking choices that have a nested textbox child sets that textbox to its default value", async () => { + mockGetValues(undefined); - const firstRadioOption = wrapper.getByRole("radio", { name: "Choice 1" }); - const secondRadioOption = wrapper.getByRole("radio", { name: "Choice 2" }); + // Create the Checkbox Component + const wrapper = render(CheckboxComponentWithNestedChildren); - // Make sure default state is set correctly - expect(firstRadioOption).not.toBeChecked(); - expect(secondRadioOption).not.toBeChecked(); + const parentCheckbox = wrapper.getByRole("checkbox", { + name: "Choice 3", + }); - // Select the first Radio and check it - fireEvent.click(firstRadioOption); + // Make sure default state is set correctly + expect(parentCheckbox).not.toBeChecked(); - // Confirm the radio options are checked correctly - const checkedOptions = wrapper.getAllByRole("radio", { - checked: true, - }); - expect(checkedOptions).toHaveLength(1); - expect(firstRadioOption).toBeChecked(); - expect(secondRadioOption).not.toBeChecked(); - - // Tab away to trigger onComponentBlur() - fireEvent.blur(firstRadioOption); - - // Make sure the form value is set to what we've clicked (Which is only Choice 1) - const firstRadioOptionOptionData = [{ key: "Choice 1", value: "Choice 1" }]; - expect(mockSetValue).toHaveBeenCalledWith( - "radioField", - firstRadioOptionOptionData, - { - shouldValidate: true, - } - ); + // Select the first Checkbox and check it + fireEvent.click(parentCheckbox); - // Now check the second radio option to trigger the onChangeHandler - fireEvent.click(secondRadioOption); + // Confirm the checkbox options are checked correctly + const checkedOptions = wrapper.getAllByRole("checkbox", { + checked: true, + }); + expect(checkedOptions).toHaveLength(1); + expect(parentCheckbox).toBeChecked(); - // Confirm the radio options are checked correctly - const uncheckedRadioOptions = wrapper.getAllByRole("radio", { - checked: false, - }); - expect(uncheckedRadioOptions).toHaveLength(1); - expect(firstRadioOption).not.toBeChecked(); - expect(secondRadioOption).toBeChecked(); - - // Tab away to trigger onComponentBlur() - fireEvent.blur(firstRadioOption); - - // Make sure the form value is set to default state - expect(mockSetValue).toHaveBeenCalledWith( - "radioField", - firstRadioOptionOptionData, - { - shouldValidate: true, - } - ); - }); + // Tab away to trigger onComponentBlur() + fireEvent.blur(parentCheckbox); - test("Checking and unchecking choices that have a nested textbox child sets that textbox to its default value", async () => { - mockGetValues(undefined); + // Make sure the form value is set to what we've clicked (Which is only Choice 3) + const parentCheckboxData = [{ key: "Choice 3", value: "Choice 3" }]; + expect(mockSetValue).toHaveBeenCalledWith( + "checkboxFieldWithNestedChildren", + parentCheckboxData, + { + shouldValidate: true, + } + ); - // Create the Checkbox Component - const wrapper = render(CheckboxComponentWithNestedChildren); + const childTextBox: HTMLInputElement = wrapper.container.querySelector( + "[name='Choice 3-otherText']" + )!; + // Now type in the child textbox + fireEvent.click(childTextBox); + fireEvent.change(childTextBox, { target: { value: "Added Text" } }); - const parentCheckbox = wrapper.getByRole("checkbox", { name: "Choice 3" }); + // Confirm the text change was made + expect(childTextBox.value).toBe("Added Text"); - // Make sure default state is set correctly - expect(parentCheckbox).not.toBeChecked(); + // Tab away to trigger onComponentBlur() + fireEvent.blur(childTextBox); - // Select the first Checkbox and check it - fireEvent.click(parentCheckbox); + // Make sure the form value is set to with new child text + expect(mockSetValue).toHaveBeenCalledWith( + "Choice 3-otherText", + "Added Text", + { + shouldValidate: true, + } + ); - // Confirm the checkbox options are checked correctly - const checkedOptions = wrapper.getAllByRole("checkbox", { - checked: true, - }); - expect(checkedOptions).toHaveLength(1); - expect(parentCheckbox).toBeChecked(); - - // Tab away to trigger onComponentBlur() - fireEvent.blur(parentCheckbox); - - // Make sure the form value is set to what we've clicked (Which is only Choice 3) - const parentCheckboxData = [{ key: "Choice 3", value: "Choice 3" }]; - expect(mockSetValue).toHaveBeenCalledWith( - "checkboxFieldWithNestedChildren", - parentCheckboxData, - { - shouldValidate: true, - } - ); + // Now uncheck the parent + fireEvent.click(parentCheckbox); - const childTextBox: HTMLInputElement = wrapper.container.querySelector( - "[name='Choice 3-otherText']" - )!; - // Now type in the child textbox - fireEvent.click(childTextBox); - fireEvent.change(childTextBox, { target: { value: "Added Text" } }); - - // Confirm the text change was made - expect(childTextBox.value).toBe("Added Text"); - - // Tab away to trigger onComponentBlur() - fireEvent.blur(childTextBox); - - // Make sure the form value is set to with new child text - expect(mockSetValue).toHaveBeenCalledWith( - "Choice 3-otherText", - "Added Text", - { - shouldValidate: true, - } - ); + // Confirm the checkbox options are unchecked correctly + const uncheckedOptions = wrapper.getAllByRole("checkbox", { + checked: false, + }); + expect(uncheckedOptions).toHaveLength(3); + expect(parentCheckbox).not.toBeChecked(); - // Now uncheck the parent - fireEvent.click(parentCheckbox); + // Tab away to trigger onComponentBlur() + fireEvent.blur(parentCheckbox); - // Confirm the checkbox options are unchecked correctly - const uncheckedOptions = wrapper.getAllByRole("checkbox", { - checked: false, - }); - expect(uncheckedOptions).toHaveLength(3); - expect(parentCheckbox).not.toBeChecked(); + // Rechecking should show the child textbox doesn't have the 'Added Text' value anymore + fireEvent.click(parentCheckbox); - // Tab away to trigger onComponentBlur() - fireEvent.blur(parentCheckbox); + // Confirm the checkbox options are checked correctly + const recheckedOptions = wrapper.getAllByRole("checkbox", { + checked: true, + }); + expect(recheckedOptions).toHaveLength(1); + expect(parentCheckbox).toBeChecked(); - // Rechecking should show the child textbox doesn't have the 'Added Text' value anymore - fireEvent.click(parentCheckbox); + const childTextBoxCleared: HTMLInputElement = + wrapper.container.querySelector("[name='Choice 3-otherText']")!; - // Confirm the checkbox options are checked correctly - const recheckedOptions = wrapper.getAllByRole("checkbox", { - checked: true, + expect(childTextBoxCleared.value).toBe(""); }); - expect(recheckedOptions).toHaveLength(1); - expect(parentCheckbox).toBeChecked(); - - const childTextBoxCleared: HTMLInputElement = - wrapper.container.querySelector("[name='Choice 3-otherText']")!; - expect(childTextBoxCleared.value).toBe(""); - }); - - test("Checking and unchecking a checkbox that has a nested radio child sets that radio to its default value (Nothing is checked)", async () => { - mockGetValues(undefined); + test("Checking and unchecking a checkbox that has a nested radio child sets that radio to its default value (Nothing is checked)", async () => { + mockGetValues(undefined); - // Create the Checkbox Component - const wrapper = render(CheckboxComponentWithNestedChildren); + // Create the Checkbox Component + const wrapper = render(CheckboxComponentWithNestedChildren); - const parentCheckbox = wrapper.getByRole("checkbox", { name: "Choice 3" }); + const parentCheckbox = wrapper.getByRole("checkbox", { + name: "Choice 3", + }); - // Make sure default state is set correctly - expect(parentCheckbox).not.toBeChecked(); + // Make sure default state is set correctly + expect(parentCheckbox).not.toBeChecked(); - // Select the first Checkbox and check it - fireEvent.click(parentCheckbox); + // Select the first Checkbox and check it + fireEvent.click(parentCheckbox); - // Confirm the checkbox options are checked correctly - const checkedOptions = wrapper.getAllByRole("checkbox", { - checked: true, - }); - expect(checkedOptions).toHaveLength(1); - expect(parentCheckbox).toBeChecked(); - - // Tab away to trigger onComponentBlur() - fireEvent.blur(parentCheckbox); - - // Make sure the form value is set to what we've clicked (Which is only Choice 3) - const parentCheckboxData = [{ key: "Choice 3", value: "Choice 3" }]; - expect(mockSetValue).toHaveBeenCalledWith( - "checkboxFieldWithNestedChildren", - parentCheckboxData, - { - shouldValidate: true, - } - ); + // Confirm the checkbox options are checked correctly + const checkedOptions = wrapper.getAllByRole("checkbox", { + checked: true, + }); + expect(checkedOptions).toHaveLength(1); + expect(parentCheckbox).toBeChecked(); - // Now check the child radio field - const childRadioField = wrapper.getByRole("radio", { - name: "Choice 4", - }); - fireEvent.click(childRadioField); - - // Confirm the option was checked - expect(childRadioField).toBeChecked(); - - // Tab away to trigger onComponentBlur() - fireEvent.blur(childRadioField); - - // Make sure the form value is set to with new child option - const childRadioData = [ - { key: "test-nested-child-radio-Choice 4", value: "Choice 4" }, - ]; - expect(mockSetValue).toHaveBeenCalledWith( - "test-nested-child-radio", - childRadioData, - { - shouldValidate: true, - } - ); + // Tab away to trigger onComponentBlur() + fireEvent.blur(parentCheckbox); - // Now uncheck the parent - fireEvent.click(parentCheckbox); + // Make sure the form value is set to what we've clicked (Which is only Choice 3) + const parentCheckboxData = [{ key: "Choice 3", value: "Choice 3" }]; + expect(mockSetValue).toHaveBeenCalledWith( + "checkboxFieldWithNestedChildren", + parentCheckboxData, + { + shouldValidate: true, + } + ); + + // Now check the child radio field + const childRadioField = wrapper.getByRole("radio", { + name: "Choice 4", + }); + fireEvent.click(childRadioField); + + // Confirm the option was checked + expect(childRadioField).toBeChecked(); + + // Tab away to trigger onComponentBlur() + fireEvent.blur(childRadioField); + + // Make sure the form value is set to with new child option + const childRadioData = [ + { key: "test-nested-child-radio-Choice 4", value: "Choice 4" }, + ]; + expect(mockSetValue).toHaveBeenCalledWith( + "test-nested-child-radio", + childRadioData, + { + shouldValidate: true, + } + ); - // Confirm the checkbox options are unchecked correctly - const uncheckedOptions = wrapper.getAllByRole("checkbox", { - checked: false, - }); - expect(uncheckedOptions).toHaveLength(3); - expect(parentCheckbox).not.toBeChecked(); + // Now uncheck the parent + fireEvent.click(parentCheckbox); - // Tab away to trigger onComponentBlur() - fireEvent.blur(parentCheckbox); + // Confirm the checkbox options are unchecked correctly + const uncheckedOptions = wrapper.getAllByRole("checkbox", { + checked: false, + }); + expect(uncheckedOptions).toHaveLength(3); + expect(parentCheckbox).not.toBeChecked(); - // Rechecking should show the child radiofield doesn't have any option checked anymore - fireEvent.click(parentCheckbox); + // Tab away to trigger onComponentBlur() + fireEvent.blur(parentCheckbox); - // Confirm the checkbox options are checked correctly - const recheckedOptions = wrapper.getAllByRole("checkbox", { - checked: true, - }); - expect(recheckedOptions).toHaveLength(1); - expect(parentCheckbox).toBeChecked(); + // Rechecking should show the child radiofield doesn't have any option checked anymore + fireEvent.click(parentCheckbox); - const childRadioCleared: HTMLInputElement = - wrapper.container.querySelector("[name='Choice 4']")!; + // Confirm the checkbox options are checked correctly + const recheckedOptions = wrapper.getAllByRole("checkbox", { + checked: true, + }); + expect(recheckedOptions).toHaveLength(1); + expect(parentCheckbox).toBeChecked(); - expect(childRadioCleared).not.toBeChecked; - }); + const childRadioCleared: HTMLInputElement = + wrapper.container.querySelector("[name='Choice 4']")!; - test("Selecting and unselecting a radio button that has nested checkbox children sets that checkbox to its default state", () => { - mockGetValues(undefined); + expect(childRadioCleared).not.toBeChecked; + }); - // Create the Radio Component - const wrapper = render(RadioComponentWithNestedChildren); + test("Selecting and unselecting a radio button that has nested checkbox children sets that checkbox to its default state", () => { + mockGetValues(undefined); - const parentRadio = wrapper.getByRole("radio", { name: "Choice 3" }); + // Create the Radio Component + const wrapper = render(RadioComponentWithNestedChildren); - // Make sure default state is set correctly - expect(parentRadio).not.toBeChecked(); + const parentRadio = wrapper.getByRole("radio", { name: "Choice 3" }); - // Select the first Radio button and check it - fireEvent.click(parentRadio); + // Make sure default state is set correctly + expect(parentRadio).not.toBeChecked(); - // Confirm the radio options are checked correctly - const selectedOptions = wrapper.getAllByRole("radio", { - checked: true, - }); - expect(selectedOptions).toHaveLength(1); - expect(parentRadio).toBeChecked(); - - // Tab away to trigger onComponentBlur() - fireEvent.blur(parentRadio); - - // Make sure the form value is set to what we've clicked (Which is only Choice 3) - const parentRadioData = [{ key: "Choice 3", value: "Choice 3" }]; - expect(mockSetValue).toHaveBeenCalledWith( - "radioFieldWithNestedChildren", - parentRadioData, - { - shouldValidate: true, - } - ); + // Select the first Radio button and check it + fireEvent.click(parentRadio); - // Now check the child radio field - const childCheckboxField = wrapper.getByRole("checkbox", { - name: "Choice 6", - }); - fireEvent.click(childCheckboxField); - - // Confirm the option was checked - expect(childCheckboxField).toBeChecked(); - - // Tab away to trigger onComponentBlur() - fireEvent.blur(childCheckboxField); - - // Make sure the form value is set to with new child option - const childCheckboxData = [ - { key: "test-nested-child-checkbox-Choice 6", value: "Choice 6" }, - ]; - expect(mockSetValue).toHaveBeenCalledWith( - "test-nested-child-checkbox", - childCheckboxData, - { - shouldValidate: true, - } - ); + // Confirm the radio options are checked correctly + const selectedOptions = wrapper.getAllByRole("radio", { + checked: true, + }); + expect(selectedOptions).toHaveLength(1); + expect(parentRadio).toBeChecked(); - const otherRadio = wrapper.getByRole("radio", { name: "Choice 1" }); + // Tab away to trigger onComponentBlur() + fireEvent.blur(parentRadio); - // Now uncheck the parent - fireEvent.click(otherRadio); + // Make sure the form value is set to what we've clicked (Which is only Choice 3) + const parentRadioData = [{ key: "Choice 3", value: "Choice 3" }]; + expect(mockSetValue).toHaveBeenCalledWith( + "radioFieldWithNestedChildren", + parentRadioData, + { + shouldValidate: true, + } + ); + + // Now check the child radio field + const childCheckboxField = wrapper.getByRole("checkbox", { + name: "Choice 6", + }); + fireEvent.click(childCheckboxField); + + // Confirm the option was checked + expect(childCheckboxField).toBeChecked(); + + // Tab away to trigger onComponentBlur() + fireEvent.blur(childCheckboxField); + + // Make sure the form value is set to with new child option + const childCheckboxData = [ + { key: "test-nested-child-checkbox-Choice 6", value: "Choice 6" }, + ]; + expect(mockSetValue).toHaveBeenCalledWith( + "test-nested-child-checkbox", + childCheckboxData, + { + shouldValidate: true, + } + ); - // Confirm the checkbox options are unchecked correctly - const unselectedOptions = wrapper.getAllByRole("radio", { - checked: false, - }); - expect(unselectedOptions).toHaveLength(2); - expect(parentRadio).not.toBeChecked(); + const otherRadio = wrapper.getByRole("radio", { name: "Choice 1" }); - // Tab away to trigger onComponentBlur() - fireEvent.blur(parentRadio); + // Now uncheck the parent + fireEvent.click(otherRadio); - // Rechecking should show the child checkbox doesn't have any option checked anymore - fireEvent.click(parentRadio); + // Confirm the checkbox options are unchecked correctly + const unselectedOptions = wrapper.getAllByRole("radio", { + checked: false, + }); + expect(unselectedOptions).toHaveLength(2); + expect(parentRadio).not.toBeChecked(); - // Confirm the checkbox options are checked correctly - const reselectedOptions = wrapper.getAllByRole("radio", { - checked: true, - }); - expect(reselectedOptions).toHaveLength(1); - expect(parentRadio).toBeChecked(); + // Tab away to trigger onComponentBlur() + fireEvent.blur(parentRadio); - const childCheckboxCleared: HTMLInputElement = - wrapper.container.querySelector("[name='Choice 6']")!; + // Rechecking should show the child checkbox doesn't have any option checked anymore + fireEvent.click(parentRadio); - expect(childCheckboxCleared).not.toBeChecked; - }); -}); + // Confirm the checkbox options are checked correctly + const reselectedOptions = wrapper.getAllByRole("radio", { + checked: true, + }); + expect(reselectedOptions).toHaveLength(1); + expect(parentRadio).toBeChecked(); -describe("ChoiceListField handles triggering validation", () => { - const choiceListFieldValidateOnRenderComponent = ( - - ); - - afterEach(() => { - jest.clearAllMocks(); - }); + const childCheckboxCleared: HTMLInputElement = + wrapper.container.querySelector("[name='Choice 6']")!; - test("Component with validateOnRender passed should validate on initial render", async () => { - mockGetValues(undefined); - render(choiceListFieldValidateOnRenderComponent); - expect(mockTrigger).toHaveBeenCalled(); + expect(childCheckboxCleared).not.toBeChecked; + }); }); -}); -describe("Test ChoiceList accessibility", () => { - beforeEach(() => { - jest.clearAllMocks(); - mockGetValues(undefined); - }); + describe("ChoiceListField handles triggering validation", () => { + const choiceListFieldValidateOnRenderComponent = ( + + ); - it("Should not have basic accessibility issues when given CheckboxField", async () => { - const { container } = render(CheckboxComponent); - const results = await axe(container); - expect(results).toHaveNoViolations(); - }); + afterEach(() => { + jest.clearAllMocks(); + }); - it("Should not have basic accessibility issues when given CheckboxField with children", async () => { - const { container } = render(CheckboxComponentWithNestedChildren); - const results = await axe(container); - expect(results).toHaveNoViolations(); + test("Component with validateOnRender passed should validate on initial render", async () => { + mockGetValues(undefined); + render(choiceListFieldValidateOnRenderComponent); + expect(mockTrigger).toHaveBeenCalled(); + }); }); - it("Should not have basic accessibility issues when given RadioField", async () => { - const { container } = render(RadioComponent); - const results = await axe(container); - expect(results).toHaveNoViolations(); - }); + describe("Test ChoiceList accessibility", () => { + beforeEach(() => { + jest.clearAllMocks(); + mockGetValues(undefined); + }); - it("Should not have basic accessibility issues when given RadioField with children", async () => { - const { container } = render(RadioComponentWithNestedChildren); - const results = await axe(container); - expect(results).toHaveNoViolations(); + testA11y(CheckboxComponent); + testA11y(CheckboxComponentWithNestedChildren); + testA11y(RadioComponent); + testA11y(RadioComponentWithNestedChildren); }); }); diff --git a/services/ui-src/src/components/fields/ChoiceListField.tsx b/services/ui-src/src/components/fields/ChoiceListField.tsx index 6843e3dce..164361d3f 100644 --- a/services/ui-src/src/components/fields/ChoiceListField.tsx +++ b/services/ui-src/src/components/fields/ChoiceListField.tsx @@ -1,19 +1,9 @@ import { useContext, useEffect, useState } from "react"; import { FieldValues, useFormContext, UseFormReturn } from "react-hook-form"; - // components import { ChoiceList as CmsdsChoiceList } from "@cmsgov/design-system"; import { Box } from "@chakra-ui/react"; import { ReportContext, EntityContext } from "components"; -// utils -import { - autosaveFieldData, - formFieldFactory, - getAutosaveFields, - labelTextWithOptional, - parseCustomHtml, - useStore, -} from "utils"; // types import { AnyObject, @@ -24,6 +14,15 @@ import { FormField, InputChangeEvent, } from "types"; +// utils +import { + autosaveFieldData, + formFieldFactory, + getAutosaveFields, + labelTextWithOptional, + parseCustomHtml, + useStore, +} from "utils"; export const ChoiceListField = ({ name, diff --git a/services/ui-src/src/components/fields/DateField.test.tsx b/services/ui-src/src/components/fields/DateField.test.tsx index 080377637..1fe9ff2a2 100644 --- a/services/ui-src/src/components/fields/DateField.test.tsx +++ b/services/ui-src/src/components/fields/DateField.test.tsx @@ -1,9 +1,10 @@ import { render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; -import { axe } from "jest-axe"; import { useFormContext } from "react-hook-form"; -//components +// components import { DateField, ReportContext } from "components"; +// types +import { ReportStatus } from "types"; // utils import { mockMcparReportContext, @@ -11,8 +12,7 @@ import { mockStateUserStore, } from "utils/testing/setupJest"; import { useStore } from "utils"; -// types -import { ReportStatus } from "types"; +import { testA11y } from "utils/testing/commonTests"; const mockTrigger = jest.fn(); const mockRhfMethods = { @@ -53,185 +53,190 @@ const dateFieldAutosavingComponent = (
); -describe("Test DateField basic functionality", () => { - test("DateField is visible", () => { - mockGetValues(undefined); - const result = render(dateFieldComponent); - const dateFieldInput: HTMLInputElement = result.container.querySelector( - "[name='testDateField']" - )!; - expect(dateFieldInput).toBeVisible(); - }); +describe("", () => { + describe("Test DateField basic functionality", () => { + test("DateField is visible", () => { + mockGetValues(undefined); + const result = render(dateFieldComponent); + const dateFieldInput: HTMLInputElement = result.container.querySelector( + "[name='testDateField']" + )!; + expect(dateFieldInput).toBeVisible(); + }); - test("onChange event fires handler when typing and stays even after blurred", async () => { - mockGetValues(undefined); - const result = render(dateFieldComponent); - const dateFieldInput: HTMLInputElement = result.container.querySelector( - "[name='testDateField']" - )!; - await userEvent.type(dateFieldInput, "07/14/2022"); - await userEvent.tab(); - expect(dateFieldInput.value).toEqual("07/14/2022"); + test("onChange event fires handler when typing and stays even after blurred", async () => { + mockGetValues(undefined); + const result = render(dateFieldComponent); + const dateFieldInput: HTMLInputElement = result.container.querySelector( + "[name='testDateField']" + )!; + await userEvent.type(dateFieldInput, "07/14/2022"); + await userEvent.tab(); + expect(dateFieldInput.value).toEqual("07/14/2022"); + }); }); -}); -describe("Test DateField hydration functionality", () => { - const mockFormFieldValue = "7/1/2022"; - const mockHydrationValue = "1/1/2022"; - - const dateFieldComponentWithHydrationValue = ( - - ); - - const clearPropGivenAndTrueDateField = ( - - ); - - const clearPropGivenAndFalseDateField = ( - - ); - - test("If only formFieldValue exists, displayValue is set to it", () => { - mockGetValues(mockFormFieldValue); - const result = render(dateFieldComponent); - const dateFieldInput: HTMLInputElement = result.container.querySelector( - "[name='testDateField']" - )!; - const displayValue = dateFieldInput.value; - expect(displayValue).toEqual(mockFormFieldValue); - }); + describe("Test DateField hydration functionality", () => { + const mockFormFieldValue = "7/1/2022"; + const mockHydrationValue = "1/1/2022"; - test("If only hydrationValue exists, displayValue is set to it", () => { - mockGetValues(undefined); - const result = render(dateFieldComponentWithHydrationValue); - const dateFieldInput: HTMLInputElement = result.container.querySelector( - "[name='testDateFieldWithHydrationValue']" - )!; - const displayValue = dateFieldInput.value; - expect(displayValue).toEqual(mockHydrationValue); - }); + const dateFieldComponentWithHydrationValue = ( + + ); - test("If both formFieldValue and hydrationValue exist, displayValue is set to formFieldValue", () => { - mockGetValues(mockFormFieldValue); - const result = render(dateFieldComponentWithHydrationValue); - const dateFieldInput: HTMLInputElement = result.container.querySelector( - "[name='testDateFieldWithHydrationValue']" - )!; - const displayValue = dateFieldInput.value; - expect(displayValue).toEqual(mockFormFieldValue); - }); + const clearPropGivenAndTrueDateField = ( + + ); - test("should set value to default if given clear prop and clear is set to true", () => { - mockGetValues(undefined); + const clearPropGivenAndFalseDateField = ( + + ); - const result = render(clearPropGivenAndTrueDateField); - const dateField: HTMLInputElement = result.container.querySelector( - "[name='testDateFieldWithHydrationValue']" - )!; - const displayValue = dateField.value; - expect(displayValue).toEqual(""); - }); + test("If only formFieldValue exists, displayValue is set to it", () => { + mockGetValues(mockFormFieldValue); + const result = render(dateFieldComponent); + const dateFieldInput: HTMLInputElement = result.container.querySelector( + "[name='testDateField']" + )!; + const displayValue = dateFieldInput.value; + expect(displayValue).toEqual(mockFormFieldValue); + }); - test("should set value to hydrationvalue if given clear prop and clear is set to false", () => { - mockGetValues(undefined); - const result = render(clearPropGivenAndFalseDateField); - const dateField: HTMLInputElement = result.container.querySelector( - "[name='testDateFieldWithHydrationValue']" - )!; - const displayValue = dateField.value; - expect(displayValue).toEqual(mockHydrationValue); - }); -}); + test("If only hydrationValue exists, displayValue is set to it", () => { + mockGetValues(undefined); + const result = render(dateFieldComponentWithHydrationValue); + const dateFieldInput: HTMLInputElement = result.container.querySelector( + "[name='testDateFieldWithHydrationValue']" + )!; + const displayValue = dateFieldInput.value; + expect(displayValue).toEqual(mockHydrationValue); + }); -describe("Test DateField autosave functionality", () => { - beforeEach(() => { - jest.clearAllMocks(); + test("If both formFieldValue and hydrationValue exist, displayValue is set to formFieldValue", () => { + mockGetValues(mockFormFieldValue); + const result = render(dateFieldComponentWithHydrationValue); + const dateFieldInput: HTMLInputElement = result.container.querySelector( + "[name='testDateFieldWithHydrationValue']" + )!; + const displayValue = dateFieldInput.value; + expect(displayValue).toEqual(mockFormFieldValue); + }); + + test("should set value to default if given clear prop and clear is set to true", () => { + mockGetValues(undefined); + + const result = render(clearPropGivenAndTrueDateField); + const dateField: HTMLInputElement = result.container.querySelector( + "[name='testDateFieldWithHydrationValue']" + )!; + const displayValue = dateField.value; + expect(displayValue).toEqual(""); + }); + + test("should set value to hydrationvalue if given clear prop and clear is set to false", () => { + mockGetValues(undefined); + const result = render(clearPropGivenAndFalseDateField); + const dateField: HTMLInputElement = result.container.querySelector( + "[name='testDateFieldWithHydrationValue']" + )!; + const displayValue = dateField.value; + expect(displayValue).toEqual(mockHydrationValue); + }); }); - test("Autosaves entered date when state user, autosave true, and field is valid", async () => { - mockTrigger.mockReturnValue(true); - mockGetValues(undefined); - render(dateFieldAutosavingComponent); - const dateField = screen.getByRole("textbox", { name: "test-date-field" }); - expect(dateField).toBeVisible(); - await userEvent.type(dateField, "07/14/2022"); - await userEvent.tab(); - expect(mockMcparReportContext.updateReport).toHaveBeenCalledTimes(1); - expect(mockMcparReportContext.updateReport).toHaveBeenCalledWith( - { - reportType: mockMcparReportContext.report.reportType, - state: mockStateUserStore.user?.state, - id: mockMcparReportContext.report.id, - }, - { - metadata: { - status: ReportStatus.IN_PROGRESS, - lastAlteredBy: mockStateUserStore.user?.full_name, + describe("Test DateField autosave functionality", () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + test("Autosaves entered date when state user, autosave true, and field is valid", async () => { + mockTrigger.mockReturnValue(true); + mockGetValues(undefined); + render(dateFieldAutosavingComponent); + const dateField = screen.getByRole("textbox", { + name: "test-date-field", + }); + expect(dateField).toBeVisible(); + await userEvent.type(dateField, "07/14/2022"); + await userEvent.tab(); + expect(mockMcparReportContext.updateReport).toHaveBeenCalledTimes(1); + expect(mockMcparReportContext.updateReport).toHaveBeenCalledWith( + { + reportType: mockMcparReportContext.report.reportType, + state: mockStateUserStore.user?.state, + id: mockMcparReportContext.report.id, }, - fieldData: { testDateField: "07/14/2022" }, - } - ); - }); + { + metadata: { + status: ReportStatus.IN_PROGRESS, + lastAlteredBy: mockStateUserStore.user?.full_name, + }, + fieldData: { testDateField: "07/14/2022" }, + } + ); + }); - test("Does not autosave if autosave is false", async () => { - mockGetValues(undefined); - render(dateFieldComponent); - const dateField = screen.getByRole("textbox", { name: "test-date-field" }); - expect(dateField).toBeVisible(); - await userEvent.type(dateField, "07/14/2022"); - await userEvent.tab(); - expect(mockMcparReportContext.updateReport).toHaveBeenCalledTimes(0); + test("Does not autosave if autosave is false", async () => { + mockGetValues(undefined); + render(dateFieldComponent); + const dateField = screen.getByRole("textbox", { + name: "test-date-field", + }); + expect(dateField).toBeVisible(); + await userEvent.type(dateField, "07/14/2022"); + await userEvent.tab(); + expect(mockMcparReportContext.updateReport).toHaveBeenCalledTimes(0); + }); }); -}); -describe("Datefield handles triggering validation", () => { - const dateFieldComponentWithValidateOnRender = ( - - ); + describe("Datefield handles triggering validation", () => { + const dateFieldComponentWithValidateOnRender = ( + + ); - afterEach(() => { - jest.clearAllMocks(); - }); + afterEach(() => { + jest.clearAllMocks(); + }); - test("Blanking field triggers form validation", async () => { - mockGetValues(undefined); - const result = render(dateFieldComponent); - expect(mockTrigger).not.toHaveBeenCalled(); - const dateFieldInput = result.getByRole("textbox", { - name: "test-date-field", + test("Blanking field triggers form validation", async () => { + mockGetValues(undefined); + const result = render(dateFieldComponent); + expect(mockTrigger).not.toHaveBeenCalled(); + const dateFieldInput = result.getByRole("textbox", { + name: "test-date-field", + }); + await userEvent.click(dateFieldInput); + await userEvent.clear(dateFieldInput); + await userEvent.tab(); + expect(mockTrigger).toHaveBeenCalled(); }); - await userEvent.click(dateFieldInput); - await userEvent.clear(dateFieldInput); - await userEvent.tab(); - expect(mockTrigger).toHaveBeenCalled(); - }); - test("Component with validateOnRender passed should validate on initial render", async () => { - mockGetValues(undefined); - render(dateFieldComponentWithValidateOnRender); - expect(mockTrigger).toHaveBeenCalled(); + test("Component with validateOnRender passed should validate on initial render", async () => { + mockGetValues(undefined); + render(dateFieldComponentWithValidateOnRender); + expect(mockTrigger).toHaveBeenCalled(); + }); }); -}); -describe("Test DateField accessibility", () => { - it("Should not have basic accessibility issues", async () => { + testA11y(dateFieldComponent, () => { mockGetValues(undefined); - const { container } = render(dateFieldComponent); - const results = await axe(container); - expect(results).toHaveNoViolations(); }); }); diff --git a/services/ui-src/src/components/fields/DropdownField.test.tsx b/services/ui-src/src/components/fields/DropdownField.test.tsx index ca946fb58..627789e5a 100644 --- a/services/ui-src/src/components/fields/DropdownField.test.tsx +++ b/services/ui-src/src/components/fields/DropdownField.test.tsx @@ -1,9 +1,10 @@ import { render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; -import { axe } from "jest-axe"; import { useFormContext } from "react-hook-form"; -//components +// components import { DropdownField, ReportContext } from "components"; +// types +import { ReportStatus } from "types"; // utils import { mockDropdownOptions, @@ -13,8 +14,7 @@ import { RouterWrappedComponent, } from "utils/testing/setupJest"; import { useStore } from "utils"; -// types -import { ReportStatus } from "types"; +import { testA11y } from "utils/testing/commonTests"; const mockTrigger = jest.fn(); const mockRhfMethods = { @@ -95,216 +95,213 @@ const dropdownComponentWithYoYCopyNoSubmittedReports = ( ); -describe("Test DropdownField basic functionality", () => { - test("Dropdown renders", () => { - mockGetValues(undefined); - render(dropdownComponentWithOptions); - const dropdown = screen.getByLabelText("test-dropdown-label"); - expect(dropdown).toBeVisible(); - }); +describe("", () => { + describe("Test DropdownField basic functionality", () => { + test("Dropdown renders", () => { + mockGetValues(undefined); + render(dropdownComponentWithOptions); + const dropdown = screen.getByLabelText("test-dropdown-label"); + expect(dropdown).toBeVisible(); + }); - test("DropdownField calls onChange function successfully", async () => { - /* - * note: because the component is not being rendered via the - * formFieldFactory, the default initial option is not being added. - * this test is written accordingly. - */ - render(dropdownComponentWithOptions); - const dropdown = screen.getByLabelText("test-dropdown-label"); - const option0 = dropdown.children.item(0) as HTMLOptionElement; - const option2 = dropdown.children.item(2) as HTMLOptionElement; - expect(option0.selected).toBe(true); - await userEvent.selectOptions(dropdown, "test-dropdown-2"); - expect(option2.selected).toBe(true); + test("DropdownField calls onChange function successfully", async () => { + /* + * note: because the component is not being rendered via the + * formFieldFactory, the default initial option is not being added. + * this test is written accordingly. + */ + render(dropdownComponentWithOptions); + const dropdown = screen.getByLabelText("test-dropdown-label"); + const option0 = dropdown.children.item(0) as HTMLOptionElement; + const option2 = dropdown.children.item(2) as HTMLOptionElement; + expect(option0.selected).toBe(true); + await userEvent.selectOptions(dropdown, "test-dropdown-2"); + expect(option2.selected).toBe(true); + }); }); -}); -describe("Test DropdownField dynamic options functionality", () => { - test("Dropdown renders dynamic options", () => { - mockGetValues(undefined); - render(dropdownComponentWithDynamicOptions); - const dropdown = screen.getByLabelText("test-dropdown-label"); - expect(dropdown.children.length).toEqual(3); + describe("Test DropdownField dynamic options functionality", () => { + test("Dropdown renders dynamic options", () => { + mockGetValues(undefined); + render(dropdownComponentWithDynamicOptions); + const dropdown = screen.getByLabelText("test-dropdown-label"); + expect(dropdown.children.length).toEqual(3); + }); }); -}); -describe("Test DropdownField hydration functionality", () => { - const mockFormFieldValue = { label: "Option 1", value: "test-dropdown-1" }; - const mockHydrationValue = { label: "Option 3", value: "test-dropdown-3" }; - const dropdownComponentWithHydrationValue = ( - - ); - - test("If only formFieldValue exists, displayValue is set to it", () => { - mockGetValues(mockFormFieldValue); - render(dropdownComponentWithOptions); - const dropdownField: HTMLSelectElement = screen.getByLabelText( - "test-dropdown-label" + describe("Test DropdownField hydration functionality", () => { + const mockFormFieldValue = { label: "Option 1", value: "test-dropdown-1" }; + const mockHydrationValue = { label: "Option 3", value: "test-dropdown-3" }; + const dropdownComponentWithHydrationValue = ( + ); - const displayValue = dropdownField.value; - expect(displayValue).toEqual(mockFormFieldValue.value); - }); - test("If only hydrationValue exists, displayValue is set to it", () => { - mockGetValues(undefined); - render(dropdownComponentWithHydrationValue); - const dropdownField: HTMLSelectElement = screen.getByLabelText( - "test-dropdown-field-to-hydrate" - ); - const displayValue = dropdownField.value; - expect(displayValue).toEqual(mockHydrationValue.value); - }); + test("If only formFieldValue exists, displayValue is set to it", () => { + mockGetValues(mockFormFieldValue); + render(dropdownComponentWithOptions); + const dropdownField: HTMLSelectElement = screen.getByLabelText( + "test-dropdown-label" + ); + const displayValue = dropdownField.value; + expect(displayValue).toEqual(mockFormFieldValue.value); + }); - test("If both formFieldValue and hydrationValue exist, displayValue is set to formFieldValue", () => { - mockGetValues(mockFormFieldValue); - render(dropdownComponentWithHydrationValue); - const dropdownField: HTMLSelectElement = screen.getByLabelText( - "test-dropdown-field-to-hydrate" - ); - const displayValue = dropdownField.value; - expect(displayValue).toEqual(mockFormFieldValue.value); - }); -}); + test("If only hydrationValue exists, displayValue is set to it", () => { + mockGetValues(undefined); + render(dropdownComponentWithHydrationValue); + const dropdownField: HTMLSelectElement = screen.getByLabelText( + "test-dropdown-field-to-hydrate" + ); + const displayValue = dropdownField.value; + expect(displayValue).toEqual(mockHydrationValue.value); + }); -describe("Test DropdownField autosaves", () => { - beforeEach(() => { - jest.clearAllMocks(); + test("If both formFieldValue and hydrationValue exist, displayValue is set to formFieldValue", () => { + mockGetValues(mockFormFieldValue); + render(dropdownComponentWithHydrationValue); + const dropdownField: HTMLSelectElement = screen.getByLabelText( + "test-dropdown-field-to-hydrate" + ); + const displayValue = dropdownField.value; + expect(displayValue).toEqual(mockFormFieldValue.value); + }); }); - test("Autosaves selected value when stateuser, autosave true, and field is valid", async () => { - mockTrigger.mockReturnValue(true); - mockGetValues(undefined); - render(dropdownComponentWithOptionsAndAutosave); - const dropDown = screen.getByLabelText("test-dropdown-label"); - expect(dropDown).toBeVisible(); - const option2 = dropDown.children.item(2) as HTMLOptionElement; - await userEvent.selectOptions(dropDown, "test-dropdown-2"); - expect(option2.selected).toBe(true); - await userEvent.tab(); - expect(mockMcparReportContext.updateReport).toHaveBeenCalledTimes(1); - expect(mockMcparReportContext.updateReport).toHaveBeenCalledWith( - { - reportType: mockMcparReportContext.report.reportType, - state: mockStateUserStore.user?.state, - id: mockMcparReportContext.report.id, - }, - { - metadata: { - status: ReportStatus.IN_PROGRESS, - lastAlteredBy: mockStateUserStore.user?.full_name, - }, - fieldData: { - testDropdown: { label: "testDropdown", value: "test-dropdown-2" }, - }, - } - ); - }); + describe("Test DropdownField autosaves", () => { + beforeEach(() => { + jest.clearAllMocks(); + }); - test("Autosaves default value when stateuser, autosave true, and field invalid", async () => { - mockTrigger.mockReturnValue(false); - mockGetValues(undefined); - render(dropdownComponentWithOptionsAndAutosave); - const dropDown = screen.getByLabelText("test-dropdown-label"); - expect(dropDown).toBeVisible(); - const option2 = dropDown.children.item(2) as HTMLOptionElement; - await userEvent.selectOptions(dropDown, "test-dropdown-2"); - expect(option2.selected).toBe(true); - await userEvent.tab(); - expect(mockMcparReportContext.updateReport).toHaveBeenCalledTimes(1); - expect(mockMcparReportContext.updateReport).toHaveBeenCalledWith( - { - reportType: mockMcparReportContext.report.reportType, - state: mockStateUserStore.user?.state, - id: mockMcparReportContext.report.id, - }, - { - metadata: { - status: ReportStatus.IN_PROGRESS, - lastAlteredBy: mockStateUserStore.user?.full_name, + test("Autosaves selected value when stateuser, autosave true, and field is valid", async () => { + mockTrigger.mockReturnValue(true); + mockGetValues(undefined); + render(dropdownComponentWithOptionsAndAutosave); + const dropDown = screen.getByLabelText("test-dropdown-label"); + expect(dropDown).toBeVisible(); + const option2 = dropDown.children.item(2) as HTMLOptionElement; + await userEvent.selectOptions(dropDown, "test-dropdown-2"); + expect(option2.selected).toBe(true); + await userEvent.tab(); + expect(mockMcparReportContext.updateReport).toHaveBeenCalledTimes(1); + expect(mockMcparReportContext.updateReport).toHaveBeenCalledWith( + { + reportType: mockMcparReportContext.report.reportType, + state: mockStateUserStore.user?.state, + id: mockMcparReportContext.report.id, }, - fieldData: { - testDropdown: { label: "- Select an option -", value: "" }, + { + metadata: { + status: ReportStatus.IN_PROGRESS, + lastAlteredBy: mockStateUserStore.user?.full_name, + }, + fieldData: { + testDropdown: { label: "testDropdown", value: "test-dropdown-2" }, + }, + } + ); + }); + + test("Autosaves default value when stateuser, autosave true, and field invalid", async () => { + mockTrigger.mockReturnValue(false); + mockGetValues(undefined); + render(dropdownComponentWithOptionsAndAutosave); + const dropDown = screen.getByLabelText("test-dropdown-label"); + expect(dropDown).toBeVisible(); + const option2 = dropDown.children.item(2) as HTMLOptionElement; + await userEvent.selectOptions(dropDown, "test-dropdown-2"); + expect(option2.selected).toBe(true); + await userEvent.tab(); + expect(mockMcparReportContext.updateReport).toHaveBeenCalledTimes(1); + expect(mockMcparReportContext.updateReport).toHaveBeenCalledWith( + { + reportType: mockMcparReportContext.report.reportType, + state: mockStateUserStore.user?.state, + id: mockMcparReportContext.report.id, }, - } - ); - }); + { + metadata: { + status: ReportStatus.IN_PROGRESS, + lastAlteredBy: mockStateUserStore.user?.full_name, + }, + fieldData: { + testDropdown: { label: "- Select an option -", value: "" }, + }, + } + ); + }); - test("Does not autosave if autosave is false", async () => { - mockGetValues(undefined); - render(dropdownComponentWithOptions); - const dropDown = screen.getByLabelText("test-dropdown-label"); - expect(dropDown).toBeVisible(); - const option2 = dropDown.children.item(2) as HTMLOptionElement; - await userEvent.selectOptions(dropDown, "test-dropdown-2"); - expect(option2.selected).toBe(true); - await userEvent.tab(); - expect(mockMcparReportContext.updateReport).toHaveBeenCalledTimes(0); + test("Does not autosave if autosave is false", async () => { + mockGetValues(undefined); + render(dropdownComponentWithOptions); + const dropDown = screen.getByLabelText("test-dropdown-label"); + expect(dropDown).toBeVisible(); + const option2 = dropDown.children.item(2) as HTMLOptionElement; + await userEvent.selectOptions(dropDown, "test-dropdown-2"); + expect(option2.selected).toBe(true); + await userEvent.tab(); + expect(mockMcparReportContext.updateReport).toHaveBeenCalledTimes(0); + }); }); -}); -describe("Dropdown handles triggering validation", () => { - const dropdownComponentWithOptionsAndValidateOnRender = ( - - ); + describe("Dropdown handles triggering validation", () => { + const dropdownComponentWithOptionsAndValidateOnRender = ( + + ); - afterEach(() => { - jest.clearAllMocks(); - }); + afterEach(() => { + jest.clearAllMocks(); + }); - test("Component with validateOnRender passed should validate on render", () => { - mockGetValues(undefined); - render(dropdownComponentWithOptionsAndValidateOnRender); - const dropdown = screen.getByLabelText("test-dropdown-label"); - expect(dropdown.children.length).toEqual(4); - expect(mockTrigger).toHaveBeenCalled(); + test("Component with validateOnRender passed should validate on render", () => { + mockGetValues(undefined); + render(dropdownComponentWithOptionsAndValidateOnRender); + const dropdown = screen.getByLabelText("test-dropdown-label"); + expect(dropdown.children.length).toEqual(4); + expect(mockTrigger).toHaveBeenCalled(); + }); }); -}); -describe("Test DropdownField accessibility", () => { - it("Should not have basic accessibility issues", async () => { - mockGetValues(undefined); - const { container } = render(dropdownComponentWithOptions); - const results = await axe(container); - expect(results).toHaveNoViolations(); + describe("Test YoY Copy options dropdown menu", () => { + test("Populates with reports", () => { + mockGetValues(undefined); + render(dropdownComponentWithYoYCopy); + const dropdown = screen.getByLabelText("test-dropdown-label"); + expect(dropdown.children.length).toEqual( + mockMcparReportContext.copyEligibleReportsByState.length + 1 + ); + }); }); -}); -describe("Test YoY Copy options dropdown menu", () => { - test("Populates with reports", () => { - mockGetValues(undefined); - render(dropdownComponentWithYoYCopy); - const dropdown = screen.getByLabelText("test-dropdown-label"); - expect(dropdown.children.length).toEqual( - mockMcparReportContext.copyEligibleReportsByState.length + 1 - ); + describe("If there are no submitted reports to copy, dropdown default value should say 'No reports eligible for copy'", () => { + test("Populates with reports", () => { + mockGetValues(undefined); + const mockNoCopyEligibleStore = { + ...mockMcparReportStore, + copyEligibleReportsByState: [], + }; + mockedUseStore.mockReturnValue({ + ...mockStateUserStore, + ...mockNoCopyEligibleStore, + }); + render(dropdownComponentWithYoYCopyNoSubmittedReports); + const dropdown = screen.getByLabelText("test-dropdown-label"); + expect(dropdown.children[0].textContent).toEqual( + "No reports eligible for copy" + ); + }); }); -}); -describe("If there are no submitted reports to copy, dropdown default value should say 'No reports eligible for copy'", () => { - test("Populates with reports", () => { + testA11y(dropdownComponentWithOptions, () => { mockGetValues(undefined); - const mockNoCopyEligibleStore = { - ...mockMcparReportStore, - copyEligibleReportsByState: [], - }; - mockedUseStore.mockReturnValue({ - ...mockStateUserStore, - ...mockNoCopyEligibleStore, - }); - render(dropdownComponentWithYoYCopyNoSubmittedReports); - const dropdown = screen.getByLabelText("test-dropdown-label"); - expect(dropdown.children[0].textContent).toEqual( - "No reports eligible for copy" - ); }); }); diff --git a/services/ui-src/src/components/fields/DropdownField.tsx b/services/ui-src/src/components/fields/DropdownField.tsx index 00b14785c..025f38aaa 100644 --- a/services/ui-src/src/components/fields/DropdownField.tsx +++ b/services/ui-src/src/components/fields/DropdownField.tsx @@ -4,15 +4,8 @@ import { useFormContext } from "react-hook-form"; import { Dropdown as CmsdsDropdown } from "@cmsgov/design-system"; import { Box } from "@chakra-ui/react"; import { ReportContext, EntityContext } from "components"; -// utils -import { - autosaveFieldData, - getAutosaveFields, - labelTextWithOptional, - parseCustomHtml, - useStore, - convertDateUtcToEt, -} from "utils"; +// constants +import { dropdownDefaultOptionText, dropdownNoReports } from "../../constants"; // types import { AnyObject, @@ -23,7 +16,15 @@ import { SelectedOption, ReportMetadataShape, } from "types"; -import { dropdownDefaultOptionText, dropdownNoReports } from "../../constants"; +// utils +import { + autosaveFieldData, + getAutosaveFields, + labelTextWithOptional, + parseCustomHtml, + useStore, + convertDateUtcToEt, +} from "utils"; export const DropdownField = ({ name, diff --git a/services/ui-src/src/components/fields/DynamicField.test.tsx b/services/ui-src/src/components/fields/DynamicField.test.tsx index e9231b8df..b44443eb3 100644 --- a/services/ui-src/src/components/fields/DynamicField.test.tsx +++ b/services/ui-src/src/components/fields/DynamicField.test.tsx @@ -1,10 +1,11 @@ import { render, screen } from "@testing-library/react"; import { act } from "react-dom/test-utils"; import userEvent from "@testing-library/user-event"; -import { axe } from "jest-axe"; import { FormProvider, useForm } from "react-hook-form"; -//components +// components import { DynamicField, ReportContext } from "components"; +// types +import { ReportStatus } from "types"; // utils import { useStore } from "utils"; import { @@ -17,8 +18,7 @@ import { mockAdminUserStore, mockMcparReportStore, } from "utils/testing/setupJest"; -// types -import { ReportStatus } from "types"; +import { testA11y } from "utils/testing/commonTests"; jest.mock("utils/state/useStore"); const mockedUseStore = useStore as jest.MockedFunction; @@ -104,379 +104,384 @@ const dynamicIlosFieldComponent = (hydrationValue?: any) => ( ); -describe("Test DynamicField component", () => { - beforeEach(async () => { - await act(async () => { - await render(dynamicFieldComponent()); +describe("", () => { + describe("Test DynamicField component", () => { + beforeEach(async () => { + await act(async () => { + await render(dynamicFieldComponent()); + }); }); - }); - - afterEach(() => { - jest.clearAllMocks(); - }); - test("DynamicField is visible", () => { - const inputBoxLabel = screen.getByText("test-label"); - expect(inputBoxLabel).toBeVisible(); - }); + afterEach(() => { + jest.clearAllMocks(); + }); - test("DynamicField append button is visible", () => { - const appendButton = screen.getByText("Add a row"); - expect(appendButton).toBeVisible(); - }); + test("DynamicField is visible", () => { + const inputBoxLabel = screen.getByText("test-label"); + expect(inputBoxLabel).toBeVisible(); + }); - test("DynamicField append button adds a field", async () => { - // click append - const appendButton = screen.getByText("Add a row"); - await userEvent.click(appendButton); + test("DynamicField append button is visible", () => { + const appendButton = screen.getByText("Add a row"); + expect(appendButton).toBeVisible(); + }); - // verify there are now two text boxes - const inputBoxLabel = screen.getAllByText("test-label"); - expect(inputBoxLabel).toHaveLength(2); - expect(appendButton).toBeVisible(); - }); + test("DynamicField append button adds a field", async () => { + // click append + const appendButton = screen.getByText("Add a row"); + await userEvent.click(appendButton); - test("DynamicField remove button removes a field", async () => { - // click append - const appendButton = screen.getByText("Add a row"); - await userEvent.click(appendButton); - - // verify there are now two text boxes - const inputBoxLabel = screen.getAllByText("test-label"); - expect(inputBoxLabel).toHaveLength(2); - expect(appendButton).toBeVisible(); - - // click remove - const removeButton = screen.queryAllByTestId("removeButton")[1]; - await userEvent.click(removeButton); - - // click delete in modal - const deleteButton = screen.getByText("Yes, delete plan"); - await userEvent.click(deleteButton); - - // verify that the field is removed - const inputBoxLabelAfterRemove = screen.getAllByText("test-label"); - expect(removeButton).not.toBeVisible(); - expect(appendButton).toBeVisible(); - expect(inputBoxLabelAfterRemove).toHaveLength(1); - }); + // verify there are now two text boxes + const inputBoxLabel = screen.getAllByText("test-label"); + expect(inputBoxLabel).toHaveLength(2); + expect(appendButton).toBeVisible(); + }); - test("DynamicField remove button can be clicked multiple times if a user doesnt submit confirmation to remove the input", async () => { - // click append - const appendButton = screen.getByText("Add a row"); - await userEvent.click(appendButton); - - // verify there are now two text boxes - const inputBoxLabel = screen.getAllByText("test-label"); - expect(inputBoxLabel).toHaveLength(2); - expect(appendButton).toBeVisible(); - - // click remove - const removeButton = screen.queryAllByTestId("removeButton")[1]; - await userEvent.click(removeButton); - - // click cancel in modal - const cancelButton = screen.getByText("Cancel"); - await userEvent.click(cancelButton); - expect(inputBoxLabel).toHaveLength(2); - expect(appendButton).toBeVisible(); - - // verify that the field can open modal again after closing - await userEvent.click(removeButton); - await userEvent.click(cancelButton); - await userEvent.click(removeButton); - await userEvent.click(cancelButton); - - expect(inputBoxLabel).toHaveLength(2); - expect(appendButton).toBeVisible(); - - // Check deletion still works - await userEvent.click(removeButton); - - // click delete in modal - const deleteButton = screen.getByText("Yes, delete plan"); - await userEvent.click(deleteButton); - - // verify that the field is removed - const inputBoxLabelAfterRemove = screen.getAllByText("test-label"); - expect(inputBoxLabelAfterRemove).toHaveLength(1); - expect(removeButton).not.toBeVisible(); - expect(appendButton).toBeVisible(); - }); + test("DynamicField remove button removes a field", async () => { + // click append + const appendButton = screen.getByText("Add a row"); + await userEvent.click(appendButton); + + // verify there are now two text boxes + const inputBoxLabel = screen.getAllByText("test-label"); + expect(inputBoxLabel).toHaveLength(2); + expect(appendButton).toBeVisible(); + + // click remove + const removeButton = screen.queryAllByTestId("removeButton")[1]; + await userEvent.click(removeButton); + + // click delete in modal + const deleteButton = screen.getByText("Yes, delete plan"); + await userEvent.click(deleteButton); + + // verify that the field is removed + const inputBoxLabelAfterRemove = screen.getAllByText("test-label"); + expect(removeButton).not.toBeVisible(); + expect(appendButton).toBeVisible(); + expect(inputBoxLabelAfterRemove).toHaveLength(1); + }); - test("Removing all dynamic fields still leaves 1 open", async () => { - // verify there is one input - const inputBoxLabel = screen.getAllByText("test-label"); - expect(inputBoxLabel).toHaveLength(1); + test("DynamicField remove button can be clicked multiple times if a user doesnt submit confirmation to remove the input", async () => { + // click append + const appendButton = screen.getByText("Add a row"); + await userEvent.click(appendButton); + + // verify there are now two text boxes + const inputBoxLabel = screen.getAllByText("test-label"); + expect(inputBoxLabel).toHaveLength(2); + expect(appendButton).toBeVisible(); + + // click remove + const removeButton = screen.queryAllByTestId("removeButton")[1]; + await userEvent.click(removeButton); + + // click cancel in modal + const cancelButton = screen.getByText("Cancel"); + await userEvent.click(cancelButton); + expect(inputBoxLabel).toHaveLength(2); + expect(appendButton).toBeVisible(); + + // verify that the field can open modal again after closing + await userEvent.click(removeButton); + await userEvent.click(cancelButton); + await userEvent.click(removeButton); + await userEvent.click(cancelButton); + + expect(inputBoxLabel).toHaveLength(2); + expect(appendButton).toBeVisible(); + + // Check deletion still works + await userEvent.click(removeButton); + + // click delete in modal + const deleteButton = screen.getByText("Yes, delete plan"); + await userEvent.click(deleteButton); + + // verify that the field is removed + const inputBoxLabelAfterRemove = screen.getAllByText("test-label"); + expect(inputBoxLabelAfterRemove).toHaveLength(1); + expect(removeButton).not.toBeVisible(); + expect(appendButton).toBeVisible(); + }); - // click remove - const removeButton = screen.queryAllByTestId("removeButton")[0]; - await userEvent.click(removeButton); + test("Removing all dynamic fields still leaves 1 open", async () => { + // verify there is one input + const inputBoxLabel = screen.getAllByText("test-label"); + expect(inputBoxLabel).toHaveLength(1); - // click delete in modal - const deleteButton = screen.getByText("Yes, delete plan"); - await userEvent.click(deleteButton); + // click remove + const removeButton = screen.queryAllByTestId("removeButton")[0]; + await userEvent.click(removeButton); - // verify that there is still one field available - const inputBoxLabelAfterRemove = screen.getAllByText("test-label"); - expect(inputBoxLabelAfterRemove).toHaveLength(1); - expect(removeButton).not.toBeVisible(); - }); -}); + // click delete in modal + const deleteButton = screen.getByText("Yes, delete plan"); + await userEvent.click(deleteButton); -describe("Test DynamicField entity deletion and deletion of associated data", () => { - beforeEach(() => { - jest.clearAllMocks(); + // verify that there is still one field available + const inputBoxLabelAfterRemove = screen.getAllByText("test-label"); + expect(inputBoxLabelAfterRemove).toHaveLength(1); + expect(removeButton).not.toBeVisible(); + }); }); - it("Deletes entity and associated sanctions and quality measure responses if state user", async () => { - await act(async () => { - await render(dynamicFieldComponent(mockHydrationPlans)); + describe("Test DynamicField entity deletion and deletion of associated data", () => { + beforeEach(() => { + jest.clearAllMocks(); }); - // delete mock-plan-1 - const removeButton = screen.queryAllByTestId("removeButton")[0]; - await userEvent.click(removeButton); - const deleteButton = screen.getByText("Yes, delete plan"); - await userEvent.click(deleteButton); - - expect(mockUpdateReport).toHaveBeenCalledWith( - { ...mockReportKeys, state: mockStateUserStore.user?.state }, - { - metadata: { - status: ReportStatus.IN_PROGRESS, - lastAlteredBy: mockStateUserStore.user?.full_name, - }, - fieldData: { - plans: [ - { - id: "mock-plan-id-2", - name: "mock-plan-2", - }, - ], - sanctions: [ - { - ...mockSanctionsEntity, - sanction_planName: { - label: "sanction_planName", - value: "mock-plan-id-2", + + test("Deletes entity and associated sanctions and quality measure responses if state user", async () => { + await act(async () => { + await render(dynamicFieldComponent(mockHydrationPlans)); + }); + // delete mock-plan-1 + const removeButton = screen.queryAllByTestId("removeButton")[0]; + await userEvent.click(removeButton); + const deleteButton = screen.getByText("Yes, delete plan"); + await userEvent.click(deleteButton); + + expect(mockUpdateReport).toHaveBeenCalledWith( + { ...mockReportKeys, state: mockStateUserStore.user?.state }, + { + metadata: { + status: ReportStatus.IN_PROGRESS, + lastAlteredBy: mockStateUserStore.user?.full_name, + }, + fieldData: { + plans: [ + { + id: "mock-plan-id-2", + name: "mock-plan-2", }, - }, - ], - qualityMeasures: [ - { - ...mockQualityMeasuresEntity, - "qualityMeasure_plan_measureResults_mock-plan-id-2": - "mock-response-2", - }, - { - ...mockQualityMeasuresEntity, - "qualityMeasure_plan_measureResults_mock-plan-id-2": - "mock-response-2", - }, - ], - }, - } - ); - }); + ], + sanctions: [ + { + ...mockSanctionsEntity, + sanction_planName: { + label: "sanction_planName", + value: "mock-plan-id-2", + }, + }, + ], + qualityMeasures: [ + { + ...mockQualityMeasuresEntity, + "qualityMeasure_plan_measureResults_mock-plan-id-2": + "mock-response-2", + }, + { + ...mockQualityMeasuresEntity, + "qualityMeasure_plan_measureResults_mock-plan-id-2": + "mock-response-2", + }, + ], + }, + } + ); + }); - it("Deletes ILOS entity and associated fields from the associated plan if state user", async () => { - await act(async () => { - await render(dynamicIlosFieldComponent(mockHydrationIlos)); + test("Deletes ILOS entity and associated fields from the associated plan if state user", async () => { + await act(async () => { + await render(dynamicIlosFieldComponent(mockHydrationIlos)); + }); + + // delete mock-ilos-1 + const removeButton = screen.queryAllByTestId("removeButton")[0]; + await userEvent.click(removeButton); + const deleteButton = screen.getByText("Yes, delete ILOS"); + await userEvent.click(deleteButton); + + expect(mockUpdateReport).toHaveBeenCalledWith( + { ...mockReportKeys, state: mockStateUserStore.user?.state }, + { + metadata: { + status: ReportStatus.IN_PROGRESS, + lastAlteredBy: mockStateUserStore.user?.full_name, + }, + fieldData: { + ilos: [], + plans: [ + { + id: "mock-plan-id-1", + "mock-drawer-text-field": "example-explanation", + name: "mock-plan-name-1", + }, + { + id: "mock-plan-id-2", + name: "mock-plan-name-2", + plan_ilosOfferedByPlan: [ + { + key: "mock-radio", + value: "Yes", + }, + ], + plan_ilosUtilizationByPlan: [], + }, + ], + qualityMeasures: [ + ...mockMcparReportStore.report!.fieldData.qualityMeasures, + ], + sanctions: [...mockMcparReportStore.report!.fieldData.sanctions], + }, + } + ); }); - // delete mock-ilos-1 - const removeButton = screen.queryAllByTestId("removeButton")[0]; - await userEvent.click(removeButton); - const deleteButton = screen.getByText("Yes, delete ILOS"); - await userEvent.click(deleteButton); - - expect(mockUpdateReport).toHaveBeenCalledWith( - { ...mockReportKeys, state: mockStateUserStore.user?.state }, - { - metadata: { - status: ReportStatus.IN_PROGRESS, - lastAlteredBy: mockStateUserStore.user?.full_name, - }, + test("If there's no ILOS entities left, associated plan responses are cleared from field data", async () => { + const mcparReportWithoutIlos = { + ...mockMcparReport, fieldData: { + ...mockMcparReport.fieldData, ilos: [], - plans: [ - { - id: "mock-plan-id-1", - "mock-drawer-text-field": "example-explanation", - name: "mock-plan-name-1", - }, - { - id: "mock-plan-id-2", - name: "mock-plan-name-2", - plan_ilosOfferedByPlan: [ - { - key: "mock-radio", - value: "Yes", - }, - ], - plan_ilosUtilizationByPlan: [], - }, - ], - qualityMeasures: [ - ...mockMcparReportStore.report!.fieldData.qualityMeasures, - ], - sanctions: [...mockMcparReportStore.report!.fieldData.sanctions], }, - } - ); - }); + }; - test("If there's no ILOS entities left, associated plan responses are cleared from field data", async () => { - const mcparReportWithoutIlos = { - ...mockMcparReport, - fieldData: { - ...mockMcparReport.fieldData, - ilos: [], - }, - }; - - const mcparReportStoreWithoutIlos = { - ...mockMcparReportStore, - report: mcparReportWithoutIlos, - }; - - mockedUseStore.mockReturnValue({ - ...mockStateUserStore, - ...mcparReportStoreWithoutIlos, - }); + const mcparReportStoreWithoutIlos = { + ...mockMcparReportStore, + report: mcparReportWithoutIlos, + }; - await act(async () => { - await render(dynamicIlosFieldComponent(mockHydrationIlos)); - }); + mockedUseStore.mockReturnValue({ + ...mockStateUserStore, + ...mcparReportStoreWithoutIlos, + }); - // delete mock-ilos-1 - const removeButton = screen.queryAllByTestId("removeButton")[0]; - await userEvent.click(removeButton); - const deleteButton = screen.getByText("Yes, delete ILOS"); - await userEvent.click(deleteButton); + await act(async () => { + await render(dynamicIlosFieldComponent(mockHydrationIlos)); + }); - expect(mockUpdateReport).toHaveBeenCalledTimes(1); - }); + // delete mock-ilos-1 + const removeButton = screen.queryAllByTestId("removeButton")[0]; + await userEvent.click(removeButton); + const deleteButton = screen.getByText("Yes, delete ILOS"); + await userEvent.click(deleteButton); - test("Admin users can't delete plans", async () => { - mockedUseStore.mockReturnValue(mockAdminUserStore); - render(dynamicFieldComponent(mockHydrationPlans)); - await act(async () => { - await render(dynamicFieldComponent(mockHydrationPlans)); + expect(mockUpdateReport).toHaveBeenCalledTimes(1); }); - // delete mock-plan-1 - const removeButton = screen.queryAllByTestId("removeButton")[0]; - await userEvent.click(removeButton); - expect(mockUpdateReport).toHaveBeenCalledTimes(0); - }); -}); -describe("Test typing into DynamicField component", () => { - test("DynamicField accepts input", async () => { - const result = render(dynamicFieldComponent()); - const firstDynamicField: HTMLInputElement = - result.container.querySelector("[name='plans[0]']")!; - expect(firstDynamicField).toBeVisible(); - await userEvent.type(firstDynamicField, "123"); - expect(firstDynamicField.value).toEqual("123"); + test("Admin users can't delete plans", async () => { + mockedUseStore.mockReturnValue(mockAdminUserStore); + render(dynamicFieldComponent(mockHydrationPlans)); + await act(async () => { + await render(dynamicFieldComponent(mockHydrationPlans)); + }); + // delete mock-plan-1 + const removeButton = screen.queryAllByTestId("removeButton")[0]; + await userEvent.click(removeButton); + expect(mockUpdateReport).toHaveBeenCalledTimes(0); + }); }); -}); -describe("Test DynamicField Autosave Functionality", () => { - beforeEach(() => { - jest.clearAllMocks(); + describe("Test typing into DynamicField component", () => { + test("DynamicField accepts input", async () => { + const result = render(dynamicFieldComponent()); + const firstDynamicField: HTMLInputElement = + result.container.querySelector("[name='plans[0]']")!; + expect(firstDynamicField).toBeVisible(); + await userEvent.type(firstDynamicField, "123"); + expect(firstDynamicField.value).toEqual("123"); + }); }); - test("Autosaves when state user", async () => { - const result = render(dynamicFieldComponent()); - const firstDynamicField: HTMLInputElement = - result.container.querySelector("[name='plans[0]']")!; - expect(firstDynamicField).toBeVisible(); - await userEvent.type(firstDynamicField, "123"); - await userEvent.tab(); - expect(mockUpdateReport).toHaveBeenCalledTimes(1); - expect(firstDynamicField.value).toBe("123"); - }); + describe("Test DynamicField Autosave Functionality", () => { + beforeEach(() => { + jest.clearAllMocks(); + }); - test("DynamicField handles blanked fields after it was filled out", async () => { - mockedUseStore.mockReturnValue({ - ...mockStateUserStore, - ...mockMcparReportStore, + test("Autosaves when state user", async () => { + const result = render(dynamicFieldComponent()); + const firstDynamicField: HTMLInputElement = + result.container.querySelector("[name='plans[0]']")!; + expect(firstDynamicField).toBeVisible(); + await userEvent.type(firstDynamicField, "123"); + await userEvent.tab(); + expect(mockUpdateReport).toHaveBeenCalledTimes(1); + expect(firstDynamicField.value).toBe("123"); }); - const result = render(dynamicFieldComponent()); - const firstDynamicField: HTMLInputElement = - result.container.querySelector("[name='plans[0]']")!; - expect(firstDynamicField).toBeVisible(); - await userEvent.type(firstDynamicField, "Plans"); - expect(firstDynamicField.value).toBe("Plans"); - await userEvent.tab(); - expect(mockUpdateReport).toHaveBeenCalledTimes(1); - expect(mockUpdateReport).lastCalledWith( - { reportType: "MCPAR", id: "mock-report-id", state: "MN" }, - { - fieldData: { - plans: [{ id: firstDynamicField.id, name: "Plans" }], - }, - metadata: { lastAlteredBy: "Thelonious States", status: "In progress" }, - } - ); - await userEvent.click(firstDynamicField); - await userEvent.clear(firstDynamicField); - await userEvent.tab(); - expect(mockUpdateReport).toHaveBeenCalledTimes(1); - expect(mockUpdateReport).lastCalledWith( - { reportType: "MCPAR", id: "mock-report-id", state: "MN" }, - { - fieldData: { - plans: [{ id: firstDynamicField.id, name: "" }], - }, - metadata: { lastAlteredBy: "Thelonious States", status: "In progress" }, - } - ); - }); - test("Autosaves and show correct number of plan inputs when bluring into adding a row", async () => { - const result = render(dynamicFieldComponent(mockHydrationPlans)); - // click append - const appendButton = screen.getByText("Add a row"); - await userEvent.click(appendButton); - const firstDynamicField: HTMLInputElement = - result.container.querySelector("[name='plans[2]']")!; - expect(firstDynamicField).toBeVisible(); - await userEvent.type(firstDynamicField, "123"); - await userEvent.click(appendButton); - // verify there are now two text boxes - const inputBoxLabel = screen.getAllByText("test-label"); - expect(inputBoxLabel).toHaveLength(4); - expect(appendButton).toBeVisible(); - expect(firstDynamicField.value).toBe("123"); - expect(mockUpdateReport).toHaveBeenCalledTimes(1); - expect(mockUpdateReport).lastCalledWith( - { reportType: "MCPAR", id: "mock-report-id", state: "MN" }, - { - fieldData: { - plans: [ - { - id: "mock-plan-id-1", - name: "mock-plan-1", - }, - { - id: "mock-plan-id-2", - name: "mock-plan-2", - }, - { id: firstDynamicField.id, name: "123" }, - ], - }, - metadata: { lastAlteredBy: "Thelonious States", status: "In progress" }, - } - ); - }); -}); + test("DynamicField handles blanked fields after it was filled out", async () => { + mockedUseStore.mockReturnValue({ + ...mockStateUserStore, + ...mockMcparReportStore, + }); + const result = render(dynamicFieldComponent()); + const firstDynamicField: HTMLInputElement = + result.container.querySelector("[name='plans[0]']")!; + expect(firstDynamicField).toBeVisible(); + await userEvent.type(firstDynamicField, "Plans"); + expect(firstDynamicField.value).toBe("Plans"); + await userEvent.tab(); + expect(mockUpdateReport).toHaveBeenCalledTimes(1); + expect(mockUpdateReport).lastCalledWith( + { reportType: "MCPAR", id: "mock-report-id", state: "MN" }, + { + fieldData: { + plans: [{ id: firstDynamicField.id, name: "Plans" }], + }, + metadata: { + lastAlteredBy: "Thelonious States", + status: "In progress", + }, + } + ); + await userEvent.click(firstDynamicField); + await userEvent.clear(firstDynamicField); + await userEvent.tab(); + expect(mockUpdateReport).toHaveBeenCalledTimes(1); + expect(mockUpdateReport).lastCalledWith( + { reportType: "MCPAR", id: "mock-report-id", state: "MN" }, + { + fieldData: { + plans: [{ id: firstDynamicField.id, name: "" }], + }, + metadata: { + lastAlteredBy: "Thelonious States", + status: "In progress", + }, + } + ); + }); -describe("Test DynamicField accessibility", () => { - it("Should not have basic accessibility issues", async () => { - const { container } = render(dynamicFieldComponent()); - const results = await axe(container); - expect(results).toHaveNoViolations(); + test("Autosaves and show correct number of plan inputs when bluring into adding a row", async () => { + const result = render(dynamicFieldComponent(mockHydrationPlans)); + // click append + const appendButton = screen.getByText("Add a row"); + await userEvent.click(appendButton); + const firstDynamicField: HTMLInputElement = + result.container.querySelector("[name='plans[2]']")!; + expect(firstDynamicField).toBeVisible(); + await userEvent.type(firstDynamicField, "123"); + await userEvent.click(appendButton); + // verify there are now two text boxes + const inputBoxLabel = screen.getAllByText("test-label"); + expect(inputBoxLabel).toHaveLength(4); + expect(appendButton).toBeVisible(); + expect(firstDynamicField.value).toBe("123"); + expect(mockUpdateReport).toHaveBeenCalledTimes(1); + expect(mockUpdateReport).lastCalledWith( + { reportType: "MCPAR", id: "mock-report-id", state: "MN" }, + { + fieldData: { + plans: [ + { + id: "mock-plan-id-1", + name: "mock-plan-1", + }, + { + id: "mock-plan-id-2", + name: "mock-plan-2", + }, + { id: firstDynamicField.id, name: "123" }, + ], + }, + metadata: { + lastAlteredBy: "Thelonious States", + status: "In progress", + }, + } + ); + }); }); + + testA11y(dynamicFieldComponent()); }); diff --git a/services/ui-src/src/components/fields/DynamicField.tsx b/services/ui-src/src/components/fields/DynamicField.tsx index d42a8edde..a114a9788 100644 --- a/services/ui-src/src/components/fields/DynamicField.tsx +++ b/services/ui-src/src/components/fields/DynamicField.tsx @@ -9,6 +9,7 @@ import { TextField, EntityContext, } from "components"; +// styles import { svgFilters } from "styles/theme"; // types import { diff --git a/services/ui-src/src/components/fields/NumberField.test.tsx b/services/ui-src/src/components/fields/NumberField.test.tsx index b7b46f179..f8da48fff 100644 --- a/services/ui-src/src/components/fields/NumberField.test.tsx +++ b/services/ui-src/src/components/fields/NumberField.test.tsx @@ -1,9 +1,10 @@ import { render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; -import { axe } from "jest-axe"; -// components import { useFormContext } from "react-hook-form"; +// components import { NumberField, ReportContext } from "components"; +// types +import { ReportStatus } from "types"; // utils import { mockMcparReportContext, @@ -11,7 +12,7 @@ import { mockStateUserStore, } from "utils/testing/setupJest"; import { useStore } from "utils"; -import { ReportStatus } from "types"; +import { testA11y } from "utils/testing/commonTests"; const mockTrigger = jest.fn(); const mockRhfMethods = { @@ -79,320 +80,319 @@ const numberFieldAutosavingComponent = ( ); -describe("Test Maskless NumberField", () => { - afterEach(() => { - jest.clearAllMocks(); - }); +describe("", () => { + describe("Test Maskless NumberField", () => { + afterEach(() => { + jest.clearAllMocks(); + }); - test("NumberField is visible", () => { - mockGetValues(undefined); - const result = render(numberFieldComponent); - const numberFieldInput: HTMLInputElement = result.container.querySelector( - "[name='testNumberField']" - )!; - expect(numberFieldInput).toBeVisible(); - }); + test("NumberField is visible", () => { + mockGetValues(undefined); + const result = render(numberFieldComponent); + const numberFieldInput: HTMLInputElement = result.container.querySelector( + "[name='testNumberField']" + )!; + expect(numberFieldInput).toBeVisible(); + }); - test("onChangeHandler updates unmasked field value", async () => { - mockGetValues(undefined); - const result = render(numberFieldComponent); - const numberFieldInput: HTMLInputElement = result.container.querySelector( - "[name='testNumberField']" - )!; - await userEvent.type(numberFieldInput, "123"); - expect(numberFieldInput.value).toEqual("123"); - await userEvent.tab(); - expect(numberFieldInput.value).toEqual("123"); + test("onChangeHandler updates unmasked field value", async () => { + mockGetValues(undefined); + const result = render(numberFieldComponent); + const numberFieldInput: HTMLInputElement = result.container.querySelector( + "[name='testNumberField']" + )!; + await userEvent.type(numberFieldInput, "123"); + expect(numberFieldInput.value).toEqual("123"); + await userEvent.tab(); + expect(numberFieldInput.value).toEqual("123"); + }); }); -}); -describe("Test Masked NumberField", () => { - beforeEach(() => { - mockGetValues(undefined); - }); - test("onChangeHandler updates comma masked field value", async () => { - const result = render(commaMaskedNumberFieldComponent); - const numberFieldInput: HTMLInputElement = result.container.querySelector( - "[name='testNumberField']" - )!; - await userEvent.type(numberFieldInput, "123"); - expect(numberFieldInput.value).toEqual("123"); - await userEvent.tab(); - expect(numberFieldInput.value).toEqual("123"); - await userEvent.clear(numberFieldInput); - await userEvent.type(numberFieldInput, "12055"); - await userEvent.tab(); - expect(numberFieldInput.value).toEqual("12,055"); - await userEvent.clear(numberFieldInput); - await userEvent.type(numberFieldInput, "12055.99"); - await userEvent.tab(); - expect(numberFieldInput.value).toEqual("12,055.99"); - await userEvent.clear(numberFieldInput); - await userEvent.type(numberFieldInput, "-1234"); - await userEvent.tab(); - expect(numberFieldInput.value).toEqual("-1,234"); - await userEvent.clear(numberFieldInput); - await userEvent.type(numberFieldInput, "$$1234567890.10"); - await userEvent.tab(); - expect(numberFieldInput.value).toEqual("$$1234567890.10"); - }); + describe("Test Masked NumberField", () => { + beforeEach(() => { + mockGetValues(undefined); + }); + test("onChangeHandler updates comma masked field value", async () => { + const result = render(commaMaskedNumberFieldComponent); + const numberFieldInput: HTMLInputElement = result.container.querySelector( + "[name='testNumberField']" + )!; + await userEvent.type(numberFieldInput, "123"); + expect(numberFieldInput.value).toEqual("123"); + await userEvent.tab(); + expect(numberFieldInput.value).toEqual("123"); + await userEvent.clear(numberFieldInput); + await userEvent.type(numberFieldInput, "12055"); + await userEvent.tab(); + expect(numberFieldInput.value).toEqual("12,055"); + await userEvent.clear(numberFieldInput); + await userEvent.type(numberFieldInput, "12055.99"); + await userEvent.tab(); + expect(numberFieldInput.value).toEqual("12,055.99"); + await userEvent.clear(numberFieldInput); + await userEvent.type(numberFieldInput, "-1234"); + await userEvent.tab(); + expect(numberFieldInput.value).toEqual("-1,234"); + await userEvent.clear(numberFieldInput); + await userEvent.type(numberFieldInput, "$$1234567890.10"); + await userEvent.tab(); + expect(numberFieldInput.value).toEqual("$$1234567890.10"); + }); - test("onChangeHandler updates Currency masked field value", async () => { - const result = render(currencyMaskedNumberFieldComponent); - const numberFieldInput: HTMLInputElement = result.container.querySelector( - "[name='testNumberField']" - )!; - await userEvent.type(numberFieldInput, "123"); - await userEvent.tab(); - expect(numberFieldInput.value).toEqual("123.00"); - await userEvent.clear(numberFieldInput); - await userEvent.type(numberFieldInput, "5.99"); - await userEvent.tab(); - expect(numberFieldInput.value).toEqual("5.99"); - await userEvent.clear(numberFieldInput); - await userEvent.type(numberFieldInput, "1234.00"); - await userEvent.tab(); - expect(numberFieldInput.value).toEqual("1,234.00"); - }); + test("onChangeHandler updates Currency masked field value", async () => { + const result = render(currencyMaskedNumberFieldComponent); + const numberFieldInput: HTMLInputElement = result.container.querySelector( + "[name='testNumberField']" + )!; + await userEvent.type(numberFieldInput, "123"); + await userEvent.tab(); + expect(numberFieldInput.value).toEqual("123.00"); + await userEvent.clear(numberFieldInput); + await userEvent.type(numberFieldInput, "5.99"); + await userEvent.tab(); + expect(numberFieldInput.value).toEqual("5.99"); + await userEvent.clear(numberFieldInput); + await userEvent.type(numberFieldInput, "1234.00"); + await userEvent.tab(); + expect(numberFieldInput.value).toEqual("1,234.00"); + }); - test("onChangeHandler updates Percentage masked field value", async () => { - const result = render(percentageMaskedNumberFieldComponent); - const numberFieldInput: HTMLInputElement = result.container.querySelector( - "[name='testNumberField']" - )!; - await userEvent.type(numberFieldInput, "123"); - expect(numberFieldInput.value).toEqual("123"); - await userEvent.tab(); - expect(numberFieldInput.value).toEqual("123"); - await userEvent.clear(numberFieldInput); - await userEvent.type(numberFieldInput, "12055"); - await userEvent.tab(); - expect(numberFieldInput.value).toEqual("12,055"); - await userEvent.clear(numberFieldInput); - await userEvent.type(numberFieldInput, "12055.99"); - await userEvent.tab(); - expect(numberFieldInput.value).toEqual("12,055.99"); - }); + test("onChangeHandler updates Percentage masked field value", async () => { + const result = render(percentageMaskedNumberFieldComponent); + const numberFieldInput: HTMLInputElement = result.container.querySelector( + "[name='testNumberField']" + )!; + await userEvent.type(numberFieldInput, "123"); + expect(numberFieldInput.value).toEqual("123"); + await userEvent.tab(); + expect(numberFieldInput.value).toEqual("123"); + await userEvent.clear(numberFieldInput); + await userEvent.type(numberFieldInput, "12055"); + await userEvent.tab(); + expect(numberFieldInput.value).toEqual("12,055"); + await userEvent.clear(numberFieldInput); + await userEvent.type(numberFieldInput, "12055.99"); + await userEvent.tab(); + expect(numberFieldInput.value).toEqual("12,055.99"); + }); - test("onChangeHandler updates ratio field value", async () => { - const result = render(ratioMaskedNumberFieldComponent); - const numberFieldInput: HTMLInputElement = result.container.querySelector( - "[name='testNumberField']" - )!; - await userEvent.type(numberFieldInput, "123:123"); - expect(numberFieldInput.value).toEqual("123:123"); - await userEvent.tab(); - expect(numberFieldInput.value).toEqual("123:123"); - await userEvent.clear(numberFieldInput); - await userEvent.type( - numberFieldInput, - "123,,,4567.1234567.1234:12,3456,7.1" - ); - await userEvent.tab(); - expect(numberFieldInput.value).toEqual( - "123,,,4567.1234567.1234:12,3456,7.1" - ); - await userEvent.clear(numberFieldInput); - await userEvent.type( - numberFieldInput, - "123,,,4567.12345671234:12,3456,7.1" - ); - await userEvent.tab(); - expect(numberFieldInput.value).toEqual("1,234,567.1234567123:1,234,567.1"); - await userEvent.clear(numberFieldInput); - await userEvent.type(numberFieldInput, ":"); - await userEvent.tab(); - expect(numberFieldInput.value).toEqual(":"); + test("onChangeHandler updates ratio field value", async () => { + const result = render(ratioMaskedNumberFieldComponent); + const numberFieldInput: HTMLInputElement = result.container.querySelector( + "[name='testNumberField']" + )!; + await userEvent.type(numberFieldInput, "123:123"); + expect(numberFieldInput.value).toEqual("123:123"); + await userEvent.tab(); + expect(numberFieldInput.value).toEqual("123:123"); + await userEvent.clear(numberFieldInput); + await userEvent.type( + numberFieldInput, + "123,,,4567.1234567.1234:12,3456,7.1" + ); + await userEvent.tab(); + expect(numberFieldInput.value).toEqual( + "123,,,4567.1234567.1234:12,3456,7.1" + ); + await userEvent.clear(numberFieldInput); + await userEvent.type( + numberFieldInput, + "123,,,4567.12345671234:12,3456,7.1" + ); + await userEvent.tab(); + expect(numberFieldInput.value).toEqual( + "1,234,567.1234567123:1,234,567.1" + ); + await userEvent.clear(numberFieldInput); + await userEvent.type(numberFieldInput, ":"); + await userEvent.tab(); + expect(numberFieldInput.value).toEqual(":"); + }); }); -}); - -describe("Test NumberField hydration functionality", () => { - const mockFormFieldValue = "54321"; - const mockHydrationValue = "12345"; - const numberFieldComponentWithHydrationValue = ( - - ); + describe("Test NumberField hydration functionality", () => { + const mockFormFieldValue = "54321"; + const mockHydrationValue = "12345"; + + const numberFieldComponentWithHydrationValue = ( + + ); - const clearPropGivenAndTrueNumberField = ( - - ); + const clearPropGivenAndTrueNumberField = ( + + ); - const clearPropGivenAndFalseNumberField = ( - - ); + const clearPropGivenAndFalseNumberField = ( + + ); - afterEach(() => { - jest.clearAllMocks(); - }); + afterEach(() => { + jest.clearAllMocks(); + }); - test("If only formFieldValue exists, displayValue is set to it", () => { - mockGetValues(mockFormFieldValue); - const result = render(numberFieldComponent); - const numberField: HTMLInputElement = result.container.querySelector( - "[name='testNumberField']" - )!; - const displayValue = numberField.value; - expect(displayValue).toEqual("54,321"); - }); + test("If only formFieldValue exists, displayValue is set to it", () => { + mockGetValues(mockFormFieldValue); + const result = render(numberFieldComponent); + const numberField: HTMLInputElement = result.container.querySelector( + "[name='testNumberField']" + )!; + const displayValue = numberField.value; + expect(displayValue).toEqual("54,321"); + }); - test("If only hydrationValue exists, displayValue is set to it", () => { - mockGetValues(undefined); - const result = render(numberFieldComponentWithHydrationValue); - const numberField: HTMLInputElement = result.container.querySelector( - "[name='testNumberFieldWithHydrationValue']" - )!; - const displayValue = numberField.value; - expect(displayValue).toEqual("12,345"); - }); + test("If only hydrationValue exists, displayValue is set to it", () => { + mockGetValues(undefined); + const result = render(numberFieldComponentWithHydrationValue); + const numberField: HTMLInputElement = result.container.querySelector( + "[name='testNumberFieldWithHydrationValue']" + )!; + const displayValue = numberField.value; + expect(displayValue).toEqual("12,345"); + }); - test("If both formFieldValue and hydrationValue exist, displayValue is set to formFieldValue", () => { - mockGetValues(mockFormFieldValue); - const result = render(numberFieldComponentWithHydrationValue); - const numberField: HTMLInputElement = result.container.querySelector( - "[name='testNumberFieldWithHydrationValue']" - )!; - const displayValue = numberField.value; - expect(displayValue).toEqual("54,321"); - }); + test("If both formFieldValue and hydrationValue exist, displayValue is set to formFieldValue", () => { + mockGetValues(mockFormFieldValue); + const result = render(numberFieldComponentWithHydrationValue); + const numberField: HTMLInputElement = result.container.querySelector( + "[name='testNumberFieldWithHydrationValue']" + )!; + const displayValue = numberField.value; + expect(displayValue).toEqual("54,321"); + }); - test("should set value to default if given clear prop and clear is set to true", () => { - mockGetValues(undefined); + test("should set value to default if given clear prop and clear is set to true", () => { + mockGetValues(undefined); - const result = render(clearPropGivenAndTrueNumberField); - const numberField: HTMLInputElement = result.container.querySelector( - "[name='testNumberField']" - )!; - const displayValue = numberField.value; - expect(displayValue).toEqual(""); - }); + const result = render(clearPropGivenAndTrueNumberField); + const numberField: HTMLInputElement = result.container.querySelector( + "[name='testNumberField']" + )!; + const displayValue = numberField.value; + expect(displayValue).toEqual(""); + }); - test("should set value to hydrationvalue if given clear prop and clear is set to false", () => { - mockGetValues(undefined); - const result = render(clearPropGivenAndFalseNumberField); - const numberField: HTMLInputElement = result.container.querySelector( - "[name='testNumberField']" - )!; - const displayValue = numberField.value; - expect(displayValue).toEqual("12,345.00"); + test("should set value to hydrationvalue if given clear prop and clear is set to false", () => { + mockGetValues(undefined); + const result = render(clearPropGivenAndFalseNumberField); + const numberField: HTMLInputElement = result.container.querySelector( + "[name='testNumberField']" + )!; + const displayValue = numberField.value; + expect(displayValue).toEqual("12,345.00"); + }); }); -}); -describe("Test NumberField component autosaves", () => { - afterEach(() => { - jest.clearAllMocks(); - }); - test("NumberField autosaves with typed value when stateuser, autosave true, and form is valid", async () => { - mockTrigger.mockReturnValue(true); - mockGetValues(undefined); - render(numberFieldAutosavingComponent); - const textField = screen.getByRole("textbox", { name: "test-label" }); - expect(textField).toBeVisible(); - await userEvent.type(textField, "1234"); - await userEvent.tab(); - expect(mockMcparReportContext.updateReport).toHaveBeenCalledTimes(1); - expect(mockMcparReportContext.updateReport).toHaveBeenCalledWith( - { - reportType: mockMcparReportContext.report.reportType, - state: mockStateUserStore.user?.state, - id: mockMcparReportContext.report.id, - }, - { - metadata: { - status: ReportStatus.IN_PROGRESS, - lastAlteredBy: mockStateUserStore.user?.full_name, + describe("Test NumberField component autosaves", () => { + afterEach(() => { + jest.clearAllMocks(); + }); + test("NumberField autosaves with typed value when stateuser, autosave true, and form is valid", async () => { + mockTrigger.mockReturnValue(true); + mockGetValues(undefined); + render(numberFieldAutosavingComponent); + const textField = screen.getByRole("textbox", { name: "test-label" }); + expect(textField).toBeVisible(); + await userEvent.type(textField, "1234"); + await userEvent.tab(); + expect(mockMcparReportContext.updateReport).toHaveBeenCalledTimes(1); + expect(mockMcparReportContext.updateReport).toHaveBeenCalledWith( + { + reportType: mockMcparReportContext.report.reportType, + state: mockStateUserStore.user?.state, + id: mockMcparReportContext.report.id, }, - fieldData: { testNumberField: "1234" }, - } - ); - }); + { + metadata: { + status: ReportStatus.IN_PROGRESS, + lastAlteredBy: mockStateUserStore.user?.full_name, + }, + fieldData: { testNumberField: "1234" }, + } + ); + }); - test("NumberField autosaves with default value when stateuser, autosave true, and form invalid", async () => { - mockTrigger.mockReturnValue(false); - mockGetValues(undefined); - render(numberFieldAutosavingComponent); - const textField = screen.getByRole("textbox", { name: "test-label" }); - expect(textField).toBeVisible(); - await userEvent.type(textField, " "); - await userEvent.tab(); - expect(mockMcparReportContext.updateReport).toHaveBeenCalledTimes(1); - expect(mockMcparReportContext.updateReport).toHaveBeenCalledWith( - { - reportType: mockMcparReportContext.report.reportType, - state: mockStateUserStore.user?.state, - id: mockMcparReportContext.report.id, - }, - { - metadata: { - status: ReportStatus.IN_PROGRESS, - lastAlteredBy: mockStateUserStore.user?.full_name, + test("NumberField autosaves with default value when stateuser, autosave true, and form invalid", async () => { + mockTrigger.mockReturnValue(false); + mockGetValues(undefined); + render(numberFieldAutosavingComponent); + const textField = screen.getByRole("textbox", { name: "test-label" }); + expect(textField).toBeVisible(); + await userEvent.type(textField, " "); + await userEvent.tab(); + expect(mockMcparReportContext.updateReport).toHaveBeenCalledTimes(1); + expect(mockMcparReportContext.updateReport).toHaveBeenCalledWith( + { + reportType: mockMcparReportContext.report.reportType, + state: mockStateUserStore.user?.state, + id: mockMcparReportContext.report.id, }, - fieldData: { testNumberField: "" }, - } - ); - }); + { + metadata: { + status: ReportStatus.IN_PROGRESS, + lastAlteredBy: mockStateUserStore.user?.full_name, + }, + fieldData: { testNumberField: "" }, + } + ); + }); - test("NumberField does not autosave if autosave is false", async () => { - mockGetValues(undefined); - render(numberFieldComponent); - const textField = screen.getByRole("textbox", { name: "test-label" }); - expect(textField).toBeVisible(); - await userEvent.type(textField, "test value"); - await userEvent.tab(); - expect(mockMcparReportContext.updateReport).toHaveBeenCalledTimes(0); + test("NumberField does not autosave if autosave is false", async () => { + mockGetValues(undefined); + render(numberFieldComponent); + const textField = screen.getByRole("textbox", { name: "test-label" }); + expect(textField).toBeVisible(); + await userEvent.type(textField, "test value"); + await userEvent.tab(); + expect(mockMcparReportContext.updateReport).toHaveBeenCalledTimes(0); + }); }); -}); -describe("Numberfield handles triggering validation", () => { - const numberFieldComponentWithValidateOnRender = ( - - ); + describe("Numberfield handles triggering validation", () => { + const numberFieldComponentWithValidateOnRender = ( + + ); - afterEach(() => { - jest.clearAllMocks(); - }); - test("Blanking field triggers form validation", async () => { - mockGetValues(undefined); - render(numberFieldComponent); - expect(mockTrigger).not.toHaveBeenCalled(); - const numberField = screen.getByRole("textbox", { - name: "test-label", + afterEach(() => { + jest.clearAllMocks(); + }); + test("Blanking field triggers form validation", async () => { + mockGetValues(undefined); + render(numberFieldComponent); + expect(mockTrigger).not.toHaveBeenCalled(); + const numberField = screen.getByRole("textbox", { + name: "test-label", + }); + expect(numberField).toBeVisible(); + await userEvent.clear(numberField); + await userEvent.tab(); + expect(mockTrigger).toHaveBeenCalled(); }); - expect(numberField).toBeVisible(); - await userEvent.clear(numberField); - await userEvent.tab(); - expect(mockTrigger).toHaveBeenCalled(); - }); - test("Component with validateOnRender passed should validate on render", async () => { - mockGetValues(undefined); - render(numberFieldComponentWithValidateOnRender); - expect(mockTrigger).toHaveBeenCalled(); + test("Component with validateOnRender passed should validate on render", async () => { + mockGetValues(undefined); + render(numberFieldComponentWithValidateOnRender); + expect(mockTrigger).toHaveBeenCalled(); + }); }); -}); -describe("Test NumberField accessibility", () => { - it("Should not have basic accessibility issues", async () => { + testA11y(numberFieldComponent, () => { mockGetValues(undefined); - const { container } = render(numberFieldComponent); - const results = await axe(container); - expect(results).toHaveNoViolations(); }); }); diff --git a/services/ui-src/src/components/fields/NumberField.tsx b/services/ui-src/src/components/fields/NumberField.tsx index a1f7bfb05..0ae766760 100644 --- a/services/ui-src/src/components/fields/NumberField.tsx +++ b/services/ui-src/src/components/fields/NumberField.tsx @@ -1,10 +1,11 @@ -/* eslint-disable @typescript-eslint/no-unused-vars */ import React, { useContext, useEffect, useState } from "react"; import { useFormContext } from "react-hook-form"; // components import { Box } from "@chakra-ui/react"; import { ReportContext, EntityContext } from "components"; import { TextField as CmsdsTextField } from "@cmsgov/design-system"; +// types +import { InputChangeEvent, AnyObject } from "types"; // utils import { applyMask, @@ -16,8 +17,6 @@ import { useStore, makeStringParseableForDatabase, } from "utils"; -// types -import { InputChangeEvent, AnyObject } from "types"; export const NumberField = ({ name, diff --git a/services/ui-src/src/components/fields/RadioField.test.tsx b/services/ui-src/src/components/fields/RadioField.test.tsx index 32c7792fa..5bc89225a 100644 --- a/services/ui-src/src/components/fields/RadioField.test.tsx +++ b/services/ui-src/src/components/fields/RadioField.test.tsx @@ -1,10 +1,11 @@ import { render, screen } from "@testing-library/react"; -import { axe } from "jest-axe"; import userEvent from "@testing-library/user-event"; -//components -import { RadioField } from "components"; import { useFormContext } from "react-hook-form"; +// components +import { RadioField } from "components"; +// utils import { mockChoices } from "utils/testing/setupJest"; +import { testA11y } from "utils/testing/commonTests"; const mockTrigger = jest.fn(); const mockSetValue = jest.fn(); @@ -35,7 +36,7 @@ const RadioFieldComponent = ( /> ); -describe("Test RadioField component", () => { +describe("", () => { test("RadioField renders as Radio", () => { mockGetValues(undefined); render(RadioFieldComponent); @@ -53,13 +54,8 @@ describe("Test RadioField component", () => { { shouldValidate: true } ); }); -}); -describe("Test RadioField accessibility", () => { - it("Should not have basic accessibility issues when given radio", async () => { + testA11y(RadioFieldComponent, () => { mockGetValues(undefined); - const { container } = render(RadioFieldComponent); - const results = await axe(container); - expect(results).toHaveNoViolations(); }); }); diff --git a/services/ui-src/src/components/fields/RadioField.tsx b/services/ui-src/src/components/fields/RadioField.tsx index 1b0de48c5..14baa3c17 100644 --- a/services/ui-src/src/components/fields/RadioField.tsx +++ b/services/ui-src/src/components/fields/RadioField.tsx @@ -1,7 +1,7 @@ // components import { Box } from "@chakra-ui/react"; import { ChoiceListField } from "components"; -// utils +// types import { ChoiceFieldProps } from "types"; export const RadioField = ({ diff --git a/services/ui-src/src/components/fields/TextAreaField.test.tsx b/services/ui-src/src/components/fields/TextAreaField.test.tsx index 71cf5a877..07ba592ea 100644 --- a/services/ui-src/src/components/fields/TextAreaField.test.tsx +++ b/services/ui-src/src/components/fields/TextAreaField.test.tsx @@ -1,7 +1,8 @@ import { render, screen } from "@testing-library/react"; -import { axe } from "jest-axe"; -//components +// components import { TextAreaField } from "components"; +// utils +import { testA11y } from "utils/testing/commonTests"; jest.mock("react-hook-form", () => ({ useFormContext: () => ({ @@ -25,12 +26,6 @@ describe("Test TextAreaField component", () => { const textAreaField = screen.getByText("test-label"); expect(textAreaField).toBeVisible(); }); -}); -describe("Test TextAreaField accessibility", () => { - it("Should not have basic accessibility issues", async () => { - const { container } = render(textAreaFieldComponent); - const results = await axe(container); - expect(results).toHaveNoViolations(); - }); + testA11y(textAreaFieldComponent); }); diff --git a/services/ui-src/src/components/fields/TextField.test.tsx b/services/ui-src/src/components/fields/TextField.test.tsx index 5fd9c4cdf..be2f36b08 100644 --- a/services/ui-src/src/components/fields/TextField.test.tsx +++ b/services/ui-src/src/components/fields/TextField.test.tsx @@ -1,9 +1,10 @@ import { render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; -import { axe } from "jest-axe"; -// components import { useFormContext } from "react-hook-form"; +// components import { ReportContext, TextField } from "components"; +// types +import { ReportStatus } from "types"; // utils import { mockMcparReportContext, @@ -11,7 +12,7 @@ import { mockStateUserStore, } from "utils/testing/setupJest"; import { useStore } from "utils"; -import { ReportStatus } from "types"; +import { testA11y } from "utils/testing/commonTests"; const mockTrigger = jest.fn(); const mockRhfMethods = { @@ -58,213 +59,209 @@ const textFieldAutosavingComponent = ( ); -describe("Test TextField component", () => { - test("TextField is visible", () => { - mockGetValues(""); - render(textFieldComponent); - const textField = screen.getByText("test-label"); - expect(textField).toBeVisible(); - jest.clearAllMocks(); +describe("", () => { + describe("Test TextField component", () => { + test("TextField is visible", () => { + mockGetValues(""); + render(textFieldComponent); + const textField = screen.getByText("test-label"); + expect(textField).toBeVisible(); + jest.clearAllMocks(); + }); }); -}); -describe("Test TextField hydration functionality", () => { - afterEach(() => { - jest.clearAllMocks(); - }); - const mockFormFieldValue = "mock-form-field-value"; - const mockHydrationValue = "mock-hydration-value"; - const textFieldComponentWithHydrationValue = ( - - ); + describe("Test TextField hydration functionality", () => { + afterEach(() => { + jest.clearAllMocks(); + }); + const mockFormFieldValue = "mock-form-field-value"; + const mockHydrationValue = "mock-hydration-value"; + const textFieldComponentWithHydrationValue = ( + + ); - const clearPropGivenAndTrueTextField = ( - - ); + const clearPropGivenAndTrueTextField = ( + + ); - const clearPropGivenAndFalseTextField = ( - - ); + const clearPropGivenAndFalseTextField = ( + + ); - test("If only formFieldValue exists, displayValue is set to it", () => { - mockGetValues(mockFormFieldValue); - const result = render(textFieldComponent); - const textField: HTMLInputElement = result.container.querySelector( - "[name='testTextField']" - )!; - const displayValue = textField.value; - expect(displayValue).toEqual(mockFormFieldValue); - }); + test("If only formFieldValue exists, displayValue is set to it", () => { + mockGetValues(mockFormFieldValue); + const result = render(textFieldComponent); + const textField: HTMLInputElement = result.container.querySelector( + "[name='testTextField']" + )!; + const displayValue = textField.value; + expect(displayValue).toEqual(mockFormFieldValue); + }); - test("If only hydrationValue exists, displayValue is set to it", () => { - mockGetValues(undefined); - const result = render(textFieldComponentWithHydrationValue); - const textField: HTMLInputElement = result.container.querySelector( - "[name='testTextFieldWithHydrationValue']" - )!; - const displayValue = textField.value; - expect(displayValue).toEqual(mockHydrationValue); - }); + test("If only hydrationValue exists, displayValue is set to it", () => { + mockGetValues(undefined); + const result = render(textFieldComponentWithHydrationValue); + const textField: HTMLInputElement = result.container.querySelector( + "[name='testTextFieldWithHydrationValue']" + )!; + const displayValue = textField.value; + expect(displayValue).toEqual(mockHydrationValue); + }); - test("If both formFieldValue and hydrationValue exist, displayValue is set to formFieldValue", () => { - mockGetValues(mockFormFieldValue); - const result = render(textFieldComponentWithHydrationValue); - const textField: HTMLInputElement = result.container.querySelector( - "[name='testTextFieldWithHydrationValue']" - )!; - const displayValue = textField.value; - expect(displayValue).toEqual(mockFormFieldValue); - }); + test("If both formFieldValue and hydrationValue exist, displayValue is set to formFieldValue", () => { + mockGetValues(mockFormFieldValue); + const result = render(textFieldComponentWithHydrationValue); + const textField: HTMLInputElement = result.container.querySelector( + "[name='testTextFieldWithHydrationValue']" + )!; + const displayValue = textField.value; + expect(displayValue).toEqual(mockFormFieldValue); + }); - test("should set value to default if given clear prop and clear is set to true", () => { - mockGetValues(undefined); + test("should set value to default if given clear prop and clear is set to true", () => { + mockGetValues(undefined); - const result = render(clearPropGivenAndTrueTextField); - const textField: HTMLInputElement = result.container.querySelector( - "[name='testTextFieldWithHydrationValue']" - )!; - const displayValue = textField.value; - expect(displayValue).toEqual(""); - }); + const result = render(clearPropGivenAndTrueTextField); + const textField: HTMLInputElement = result.container.querySelector( + "[name='testTextFieldWithHydrationValue']" + )!; + const displayValue = textField.value; + expect(displayValue).toEqual(""); + }); - test("should set value to hydrationvalue if given clear prop and clear is set to false", () => { - mockGetValues(undefined); - const result = render(clearPropGivenAndFalseTextField); - const textField: HTMLInputElement = result.container.querySelector( - "[name='testTextFieldWithHydrationValue']" - )!; - const displayValue = textField.value; - expect(displayValue).toEqual(mockHydrationValue); + test("should set value to hydrationvalue if given clear prop and clear is set to false", () => { + mockGetValues(undefined); + const result = render(clearPropGivenAndFalseTextField); + const textField: HTMLInputElement = result.container.querySelector( + "[name='testTextFieldWithHydrationValue']" + )!; + const displayValue = textField.value; + expect(displayValue).toEqual(mockHydrationValue); + }); }); -}); -describe("Test TextField component autosaves", () => { - afterEach(() => { - jest.clearAllMocks(); - }); - test("TextField autosaves with typed value when stateuser, autosave true, and form is valid", async () => { - mockTrigger.mockReturnValue(true); - mockGetValues(undefined); - render(textFieldAutosavingComponent); - const textField = screen.getByRole("textbox", { - name: "test-label", + describe("Test TextField component autosaves", () => { + afterEach(() => { + jest.clearAllMocks(); }); - expect(textField).toBeVisible(); - await userEvent.type(textField, "test value"); - await userEvent.tab(); - expect(mockMcparReportContext.updateReport).toHaveBeenCalledTimes(1); - expect(mockMcparReportContext.updateReport).toHaveBeenCalledWith( - { - reportType: mockMcparReportContext.report.reportType, - state: mockStateUserStore.user?.state, - id: mockMcparReportContext.report.id, - }, - { - metadata: { - status: ReportStatus.IN_PROGRESS, - lastAlteredBy: mockStateUserStore.user?.full_name, + test("TextField autosaves with typed value when stateuser, autosave true, and form is valid", async () => { + mockTrigger.mockReturnValue(true); + mockGetValues(undefined); + render(textFieldAutosavingComponent); + const textField = screen.getByRole("textbox", { + name: "test-label", + }); + expect(textField).toBeVisible(); + await userEvent.type(textField, "test value"); + await userEvent.tab(); + expect(mockMcparReportContext.updateReport).toHaveBeenCalledTimes(1); + expect(mockMcparReportContext.updateReport).toHaveBeenCalledWith( + { + reportType: mockMcparReportContext.report.reportType, + state: mockStateUserStore.user?.state, + id: mockMcparReportContext.report.id, }, - fieldData: { testTextField: "test value" }, - } - ); - }); - - test("TextField autosaves with default value when stateuser, autosave true, and form invalid", async () => { - mockTrigger.mockReturnValue(false); - mockGetValues(undefined); - render(textFieldAutosavingComponent); - const textField = screen.getByRole("textbox", { - name: "test-label", + { + metadata: { + status: ReportStatus.IN_PROGRESS, + lastAlteredBy: mockStateUserStore.user?.full_name, + }, + fieldData: { testTextField: "test value" }, + } + ); }); - expect(textField).toBeVisible(); - await userEvent.type(textField, "test value"); - await userEvent.tab(); - expect(mockMcparReportContext.updateReport).toHaveBeenCalledTimes(1); - expect(mockMcparReportContext.updateReport).toHaveBeenCalledWith( - { - reportType: mockMcparReportContext.report.reportType, - state: mockStateUserStore.user?.state, - id: mockMcparReportContext.report.id, - }, - { - metadata: { - status: ReportStatus.IN_PROGRESS, - lastAlteredBy: mockStateUserStore.user?.full_name, + + test("TextField autosaves with default value when stateuser, autosave true, and form invalid", async () => { + mockTrigger.mockReturnValue(false); + mockGetValues(undefined); + render(textFieldAutosavingComponent); + const textField = screen.getByRole("textbox", { + name: "test-label", + }); + expect(textField).toBeVisible(); + await userEvent.type(textField, "test value"); + await userEvent.tab(); + expect(mockMcparReportContext.updateReport).toHaveBeenCalledTimes(1); + expect(mockMcparReportContext.updateReport).toHaveBeenCalledWith( + { + reportType: mockMcparReportContext.report.reportType, + state: mockStateUserStore.user?.state, + id: mockMcparReportContext.report.id, }, - fieldData: { testTextField: "" }, - } - ); - }); + { + metadata: { + status: ReportStatus.IN_PROGRESS, + lastAlteredBy: mockStateUserStore.user?.full_name, + }, + fieldData: { testTextField: "" }, + } + ); + }); - test("TextField does not autosave when not autosave not set to true", async () => { - mockGetValues(undefined); - render(textFieldComponent); - const textField = screen.getByRole("textbox", { - name: "test-label", + test("TextField does not autosave when not autosave not set to true", async () => { + mockGetValues(undefined); + render(textFieldComponent); + const textField = screen.getByRole("textbox", { + name: "test-label", + }); + expect(textField).toBeVisible(); + await userEvent.type(textField, "test value"); + await userEvent.tab(); + expect(mockMcparReportContext.updateReport).toHaveBeenCalledTimes(0); }); - expect(textField).toBeVisible(); - await userEvent.type(textField, "test value"); - await userEvent.tab(); - expect(mockMcparReportContext.updateReport).toHaveBeenCalledTimes(0); }); -}); -describe("Textfield handles triggering validation", () => { - const textFieldValidateOnRenderComponent = ( - - ); + describe("Textfield handles triggering validation", () => { + const textFieldValidateOnRenderComponent = ( + + ); - afterEach(() => { - jest.clearAllMocks(); - }); - test("Blanking field triggers form validation", async () => { - mockGetValues(undefined); - render(textFieldComponent); - expect(mockTrigger).not.toHaveBeenCalled(); - const textField = screen.getByRole("textbox", { - name: "test-label", + afterEach(() => { + jest.clearAllMocks(); + }); + test("Blanking field triggers form validation", async () => { + mockGetValues(undefined); + render(textFieldComponent); + expect(mockTrigger).not.toHaveBeenCalled(); + const textField = screen.getByRole("textbox", { + name: "test-label", + }); + expect(textField).toBeVisible(); + await userEvent.clear(textField); + await userEvent.tab(); + expect(mockTrigger).toHaveBeenCalled(); }); - expect(textField).toBeVisible(); - await userEvent.clear(textField); - await userEvent.tab(); - expect(mockTrigger).toHaveBeenCalled(); - }); - test("Component with validateOnRender passed should validate on initial render", async () => { - mockGetValues(undefined); - render(textFieldValidateOnRenderComponent); - expect(mockTrigger).toHaveBeenCalled(); + test("Component with validateOnRender passed should validate on initial render", async () => { + mockGetValues(undefined); + render(textFieldValidateOnRenderComponent); + expect(mockTrigger).toHaveBeenCalled(); + }); }); -}); -describe("Test TextField accessibility", () => { - it("Should not have basic accessibility issues", async () => { + testA11y(textFieldComponent, () => { mockGetValues(undefined); - const { container } = render(textFieldComponent); - const results = await axe(container); - expect(results).toHaveNoViolations(); - jest.clearAllMocks(); }); }); diff --git a/services/ui-src/src/components/fields/TextField.tsx b/services/ui-src/src/components/fields/TextField.tsx index 54493b10f..fa688420e 100644 --- a/services/ui-src/src/components/fields/TextField.tsx +++ b/services/ui-src/src/components/fields/TextField.tsx @@ -4,6 +4,8 @@ import { useFormContext } from "react-hook-form"; import { TextField as CmsdsTextField } from "@cmsgov/design-system"; import { Box } from "@chakra-ui/react"; import { ReportContext, EntityContext } from "components"; +// types +import { InputChangeEvent, AnyObject, CustomHtmlElement } from "types"; // utils import { autosaveFieldData, @@ -12,8 +14,6 @@ import { parseCustomHtml, useStore, } from "utils"; -// types -import { InputChangeEvent, AnyObject, CustomHtmlElement } from "types"; export const TextField = ({ name, diff --git a/services/ui-src/src/components/forms/AdminBannerForm.test.tsx b/services/ui-src/src/components/forms/AdminBannerForm.test.tsx index c3cb341b8..49565d7cf 100644 --- a/services/ui-src/src/components/forms/AdminBannerForm.test.tsx +++ b/services/ui-src/src/components/forms/AdminBannerForm.test.tsx @@ -1,12 +1,13 @@ import { render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; -import { axe } from "jest-axe"; // components import { AdminBannerForm } from "components"; +// constants import { bannerId } from "../../constants"; // utils import { convertDateTimeEtToUtc } from "utils"; import { RouterWrappedComponent } from "utils/testing/mockRouter"; +import { testA11y } from "utils/testing/commonTests"; const mockWriteAdminBanner = jest.fn(); const mockWriteAdminBannerWithError = jest.fn(() => { @@ -36,7 +37,7 @@ const fillOutForm = async (form: any) => { await userEvent.tab(); }; -describe("Test AdminBannerForm component", () => { +describe("", () => { test("AdminBannerForm is visible", () => { render(adminBannerFormComponent(mockWriteAdminBanner)); const form = screen.getByTestId("test-form"); @@ -76,14 +77,6 @@ describe("Test AdminBannerForm component", () => { await userEvent.click(submitButton); expect(screen.getByText(/Something went wrong on our end/)).toBeVisible(); }); -}); -describe("Test AdminBannerForm accessibility", () => { - it("Should not have basic accessibility issues", async () => { - const { container } = render( - adminBannerFormComponent(mockWriteAdminBanner) - ); - const results = await axe(container); - expect(results).toHaveNoViolations(); - }); + testA11y(adminBannerFormComponent(mockWriteAdminBanner)); }); diff --git a/services/ui-src/src/components/forms/AdminBannerForm.tsx b/services/ui-src/src/components/forms/AdminBannerForm.tsx index d135254c7..96c629dd5 100644 --- a/services/ui-src/src/components/forms/AdminBannerForm.tsx +++ b/services/ui-src/src/components/forms/AdminBannerForm.tsx @@ -2,12 +2,15 @@ import { useState } from "react"; // components import { Button, Flex, Spinner } from "@chakra-ui/react"; import { ErrorAlert, Form, PreviewBanner } from "components"; -// utils +// constants import { bannerId } from "../../constants"; -import { bannerErrors } from "verbiage/errors"; -import { convertDatetimeStringToNumber } from "utils"; +// types import { AlertTypes, ErrorVerbiage, FormJson } from "types"; -// data +// utils +import { convertDatetimeStringToNumber } from "utils"; +// verbiage +import { bannerErrors } from "verbiage/errors"; +// form import formJson from "forms/addAdminBanner/addAdminBanner.json"; export const AdminBannerForm = ({ writeAdminBanner, ...props }: Props) => { diff --git a/services/ui-src/src/components/forms/AdminDashSelector.test.tsx b/services/ui-src/src/components/forms/AdminDashSelector.test.tsx index 1d3b4fe4d..84d19e157 100644 --- a/services/ui-src/src/components/forms/AdminDashSelector.test.tsx +++ b/services/ui-src/src/components/forms/AdminDashSelector.test.tsx @@ -1,5 +1,4 @@ import { fireEvent, render, screen } from "@testing-library/react"; -import { axe } from "jest-axe"; import userEvent from "@testing-library/user-event"; // components import { AdminDashSelector } from "components"; @@ -11,6 +10,7 @@ import { RouterWrappedComponent, } from "utils/testing/setupJest"; import { useStore } from "utils"; +import { testA11y } from "utils/testing/commonTests"; // verbiage import verbiage from "verbiage/pages/home"; @@ -33,55 +33,51 @@ mockLDFlags.setDefault({ naaarReport: true }); // TESTS -describe("Test AdminDashSelector view", () => { - test("Check that AdminDashSelector view renders", () => { - render(adminDashSelectorView); - expect(screen.getByText(verbiage.readOnly.header)).toBeVisible(); - }); +describe("", () => { + describe("Test AdminDashSelector view", () => { + test("Check that AdminDashSelector view renders", () => { + render(adminDashSelectorView); + expect(screen.getByText(verbiage.readOnly.header)).toBeVisible(); + }); - test("Check that submit button is disabled if no report type is selected", () => { - render(adminDashSelectorView); - expect(screen.getByRole("button").hasAttribute("disabled")).toBeTruthy; - }); + test("Check that submit button is disabled if no report type is selected", () => { + render(adminDashSelectorView); + expect(screen.getByRole("button").hasAttribute("disabled")).toBeTruthy; + }); - test("Form submits correctly", async () => { - const result = render(adminDashSelectorView); - const form = result.container; - const dropdownInput = form.querySelector("[name='state']")!; - await fireEvent.change(dropdownInput, { target: { value: "CA" } }); - const reportInput = form.querySelector("[name='report']")!; - fireEvent.click(reportInput, { target: { value: "MCPAR" } }); - const submitButton = screen.getByRole("button"); - await userEvent.click(submitButton); - expect(window.location.pathname).toEqual("/mcpar"); + test("Form submits correctly", async () => { + const result = render(adminDashSelectorView); + const form = result.container; + const dropdownInput = form.querySelector("[name='state']")!; + await fireEvent.change(dropdownInput, { target: { value: "CA" } }); + const reportInput = form.querySelector("[name='report']")!; + fireEvent.click(reportInput, { target: { value: "MCPAR" } }); + const submitButton = screen.getByRole("button"); + await userEvent.click(submitButton); + expect(window.location.pathname).toEqual("/mcpar"); + }); }); -}); -describe("Test naaarReport feature flag functionality", () => { - test("if naaarReport flag is true, NAAAR radio choice should be visible", async () => { - mockLDFlags.set({ naaarReport: true }); - render(adminDashSelectorView); - expect( - screen.getByLabelText( - "Network Adequacy and Access Assurances Report (NAAAR)" - ) - ).toBeVisible(); - }); + describe("Test naaarReport feature flag functionality", () => { + test("if naaarReport flag is true, NAAAR radio choice should be visible", async () => { + mockLDFlags.set({ naaarReport: true }); + render(adminDashSelectorView); + expect( + screen.getByLabelText( + "Network Adequacy and Access Assurances Report (NAAAR)" + ) + ).toBeVisible(); + }); - test("if naaarReport flag is false, NAAAR available verbiage should not be visible", async () => { - mockLDFlags.set({ naaarReport: false }); - render(adminDashSelectorView); - const naaarRadioChoice = screen.queryByLabelText( - "Network Adequacy and Access Assurances Report (NAAAR)" - ); - expect(naaarRadioChoice).toBeNull(); + test("if naaarReport flag is false, NAAAR available verbiage should not be visible", async () => { + mockLDFlags.set({ naaarReport: false }); + render(adminDashSelectorView); + const naaarRadioChoice = screen.queryByLabelText( + "Network Adequacy and Access Assurances Report (NAAAR)" + ); + expect(naaarRadioChoice).toBeNull(); + }); }); -}); -describe("Test AdminDashSelector view accessibility", () => { - it("Should not have basic accessibility issues", async () => { - const { container } = render(adminDashSelectorView); - const results = await axe(container); - expect(results).toHaveNoViolations(); - }); + testA11y(adminDashSelectorView); }); diff --git a/services/ui-src/src/components/forms/AdminDashSelector.tsx b/services/ui-src/src/components/forms/AdminDashSelector.tsx index c4144b6ff..9bb027e7e 100644 --- a/services/ui-src/src/components/forms/AdminDashSelector.tsx +++ b/services/ui-src/src/components/forms/AdminDashSelector.tsx @@ -6,10 +6,10 @@ import { Box, Button, Flex, Heading } from "@chakra-ui/react"; import { Form } from "components"; // types import { AnyObject, FormJson, InputChangeEvent } from "types"; -// form -import formJson from "forms/adminDashSelector/adminDashSelector"; // utils import { useStore } from "utils"; +// form +import formJson from "forms/adminDashSelector/adminDashSelector"; export const AdminDashSelector = ({ verbiage }: Props) => { const navigate = useNavigate(); diff --git a/services/ui-src/src/components/forms/Form.test.tsx b/services/ui-src/src/components/forms/Form.test.tsx index 2b23026c1..03993cc6b 100644 --- a/services/ui-src/src/components/forms/Form.test.tsx +++ b/services/ui-src/src/components/forms/Form.test.tsx @@ -1,8 +1,9 @@ import { render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; -import { axe } from "jest-axe"; // components import { Form } from "components"; +// types +import { ReportStatus } from "types"; // utils import { mockForm, @@ -13,8 +14,7 @@ import { RouterWrappedComponent, } from "utils/testing/setupJest"; import { useStore } from "utils"; -// types -import { ReportStatus } from "types"; +import { testA11y } from "utils/testing/commonTests"; const mockOnSubmit = jest.fn(); @@ -55,7 +55,7 @@ const formComponentJustHeader = ( ); -describe("Test Form component", () => { +describe("
", () => { test("Form is visible", () => { render(formComponent); const form = screen.getByText(mockForm.fields[0].props.label); @@ -113,12 +113,6 @@ describe("Test Form component", () => { expect(x).toBeDisabled(); }); }); -}); -describe("Test Form accessibility", () => { - it("Should not have basic accessibility issues", async () => { - const { container } = render(formComponent); - const results = await axe(container); - expect(results).toHaveNoViolations(); - }); + testA11y(formComponent); }); diff --git a/services/ui-src/src/components/forms/Form.tsx b/services/ui-src/src/components/forms/Form.tsx index 8c50d40bb..8209bec3e 100644 --- a/services/ui-src/src/components/forms/Form.tsx +++ b/services/ui-src/src/components/forms/Form.tsx @@ -10,15 +10,6 @@ import { object as yupSchema } from "yup"; import { yupResolver } from "@hookform/resolvers/yup"; // components import { Box } from "@chakra-ui/react"; -// utils -import { - compileValidationJsonFromFields, - formFieldFactory, - hydrateFormFields, - mapValidationTypesToSchema, - sortFormErrors, - useStore, -} from "utils"; // types import { AnyObject, @@ -28,6 +19,15 @@ import { FormLayoutElement, ReportStatus, } from "types"; +// utils +import { + compileValidationJsonFromFields, + formFieldFactory, + hydrateFormFields, + mapValidationTypesToSchema, + sortFormErrors, + useStore, +} from "utils"; export const Form = ({ id, diff --git a/services/ui-src/src/components/forms/FormLayoutElements.test.tsx b/services/ui-src/src/components/forms/FormLayoutElements.test.tsx index 227e60d14..cb4aca519 100644 --- a/services/ui-src/src/components/forms/FormLayoutElements.test.tsx +++ b/services/ui-src/src/components/forms/FormLayoutElements.test.tsx @@ -1,6 +1,8 @@ import { render, screen } from "@testing-library/react"; -import { axe } from "jest-axe"; +import { testA11y } from "utils/testing/commonTests"; +// components import { SectionContent, SectionHeader } from "./FormLayoutElements"; +// utils const sectionHeaderComponentTopDivider = ( ; -describe("Test SectionHeader component", () => { +describe("", () => { test("Top should make the section divider on the top.", async () => { const { findByText, getByRole } = render(sectionHeaderComponentTopDivider); const sectionHeader = screen.getByTestId("test-section-header"); @@ -60,27 +62,18 @@ describe("Test SectionHeader component", () => { expect(await findByText("1. Section Header")).toBeTruthy(); expect(queryByRole("separator")).not.toBeInTheDocument(); }); + + testA11y(sectionHeaderComponentBottomDivider); + testA11y(sectionHeaderComponentTopDivider); + testA11y(sectionHeaderComponentNoDivider); }); -describe("Test SectionContent component", () => { +describe("", () => { test("Component should be visible and render correct text.", async () => { const { findByText } = render(sectionContentComponent); expect(await findByText("Foo")).toBeTruthy(); expect(await findByText("Foo")).toBeVisible(); }); -}); -describe("Test FormLayoutElements components accessibility", () => { - it("Should not have basic accessibility issues", async () => { - for (const component of [ - sectionHeaderComponentBottomDivider, - sectionHeaderComponentTopDivider, - sectionHeaderComponentNoDivider, - sectionContentComponent, - ]) { - const { container } = render(component); - const results = await axe(container); - expect(results).toHaveNoViolations(); - } - }); + testA11y(sectionContentComponent); }); diff --git a/services/ui-src/src/components/forms/FormLayoutElements.tsx b/services/ui-src/src/components/forms/FormLayoutElements.tsx index de4ce6b3e..3c83d3be4 100644 --- a/services/ui-src/src/components/forms/FormLayoutElements.tsx +++ b/services/ui-src/src/components/forms/FormLayoutElements.tsx @@ -1,3 +1,4 @@ +// components import { Box, Heading, Text } from "@chakra-ui/react"; export const SectionHeader = ({ diff --git a/services/ui-src/src/components/layout/Footer.test.tsx b/services/ui-src/src/components/layout/Footer.test.tsx index 8b03945e4..c3babc514 100644 --- a/services/ui-src/src/components/layout/Footer.test.tsx +++ b/services/ui-src/src/components/layout/Footer.test.tsx @@ -1,9 +1,9 @@ import { render, screen } from "@testing-library/react"; -import { axe } from "jest-axe"; +// components +import { Footer } from "components"; +import { testA11y } from "utils/testing/commonTests"; // utils import { RouterWrappedComponent } from "utils/testing/setupJest"; -//components -import { Footer } from "components"; const footerComponent = ( @@ -11,29 +11,25 @@ const footerComponent = ( ); -describe("Test Footer", () => { - beforeEach(() => { - render(footerComponent); - }); +describe("