From fe8836451585a6b38f4bf442b4ec8ed46799f479 Mon Sep 17 00:00:00 2001 From: Nick Clyde Date: Wed, 1 Dec 2021 08:28:29 -0800 Subject: [PATCH] Fix a whole bunch of frontend test issues (#3028) * Remove pending org edit tests for now * Add eslint-plugin-testing-library * Fix lint errors for PendingOrganizationsContainer.test.tsx * Start fixing new lint errors * Add eslint-plugin-unused-imports * Continue fixing lint errors * Continue fixing lint rules * Finish fixing lints * Replace react-test-renderer with testing-library everywhere * Clean up some console warnings * Keep working at AddPatient.test.tsx * Clean up unused vars * Replace unused vars for i18n constants * Suppress moment deprecation warning in setupTests.js * Fix AddPatient.test.tsx * Suppress DOMException in QueueItem.test.tsx * Remove remaining act() calls * Bump up Jest timeout globally to prevent 'createEvent' TypeError * Exclude frontend test setup file from sonar coverage * Remove unnecessary cleanup calls * Add eslint-plugin-jest-dom --- backend/build.gradle | 1 + frontend/package.json | 44 +- frontend/src/app/App.test.tsx | 17 +- .../Components/ManageDevices.test.tsx | 56 +- .../Facility/Components/ManageDevices.tsx | 1 - .../Facility/FacilityFormContainer.test.tsx | 24 +- .../src/app/Settings/FacilityForm.test.tsx | 48 +- .../app/Settings/ManageOrganization.test.tsx | 16 +- .../ManageSelfRegistrationLinks.test.tsx | 10 +- .../app/Settings/Users/ManageUsers.test.tsx | 357 ++- .../src/app/Settings/Users/UsersSideNav.tsx | 7 + .../__snapshots__/ManageUsers.test.tsx.snap | 673 ----- .../MfaEmailVerify/MfaEmailVerify.test.tsx | 21 +- .../MfaGoogleAuthVerify.test.tsx | 21 +- .../MfaOktaVerify/MfaOktaVerify.test.tsx | 21 +- .../MfaPhone/MfaPhone.test.tsx | 49 +- .../MfaPhoneVerify/MfaPhoneVerify.test.tsx | 21 +- .../MfaSecurityKey/MfaSecurityKey.test.tsx | 22 +- .../MfaSelect/MfaSelect.test.tsx | 12 +- .../accountCreation/MfaSms/MfaSms.test.tsx | 49 +- .../MfaSmsVerify/MfaSmsVerify.test.tsx | 21 +- .../PasswordCreate/PasswordCreate.test.tsx | 21 +- .../SecurityQuestion.test.tsx | 21 +- frontend/src/app/analytics/Analytics.test.tsx | 109 +- .../MultiSelectDropdown.test.tsx | 382 +-- .../commonComponents/NewFeatureTag.test.tsx | 2 +- .../app/commonComponents/Page/Page.test.tsx | 6 +- .../app/commonComponents/Pagination.test.tsx | 2 +- .../__test__/ErrorPage.test.tsx | 11 +- .../commonComponents/__test__/Header.test.tsx | 16 +- .../__test__/LinkWithQuery.test.tsx | 12 +- .../__snapshots__/ErrorPage.test.tsx.snap | 103 - frontend/src/app/constants/index.tsx | 1 + .../facilitySelect/FacilitySelect.test.tsx | 16 +- .../app/facilitySelect/WithFacility.test.tsx | 32 +- .../FacilitySelect.test.tsx.snap | 64 - .../__snapshots__/WithFacility.test.tsx.snap | 112 - .../MfaAuthenticationApp.test.tsx | 2 +- .../src/app/login/MfaPhone/MfaPhone.test.tsx | 2 +- .../src/app/patients/AddPatient.stories.tsx | 2 +- frontend/src/app/patients/AddPatient.test.tsx | 354 +-- .../patients/Components/ManageEmails.test.tsx | 4 +- .../app/patients/Components/ManageEmails.tsx | 1 - .../Components/ManagePhoneNumbers.tsx | 2 +- .../src/app/patients/EditPatient.test.tsx | 56 +- .../IdentityVerification/Consent.test.tsx | 2 +- .../PersonalDetailsForm.test.tsx | 150 +- .../QuestionsForm.test.tsx | 121 +- .../QuestionsFormContainer.test.tsx | 90 +- .../Organization/OrganizationForm.test.tsx | 48 +- .../signUp/Organization/SignUpGoals.test.tsx | 2 +- ...AddOrganizationAdminFormContainer.test.tsx | 76 +- .../DeviceType/DeviceTypeForm.test.tsx | 10 +- .../DeviceTypeFormContainer.test.tsx | 20 +- .../ManageDeviceTypeFormContainer.test.tsx | 22 +- .../DeviceType/ManageDevicesForm.test.tsx | 10 +- .../PendingOrganizationsContainer.test.tsx | 187 +- .../TenantDataAccessForm.test.tsx | 14 +- .../TenantDataAccessFormContainer.test.tsx | 17 +- .../app/testQueue/AoEForm/AoEForm.test.tsx | 47 +- .../src/app/testQueue/AoEForm/AoEForm.tsx | 2 +- .../testQueue/AoEForm/AoEModalForm.test.tsx | 2 +- .../testQueue/AoEForm/SymptomInputs.test.tsx | 57 +- .../__snapshots__/AoEForm.test.tsx.snap | 648 ----- .../__snapshots__/SymptomInputs.test.tsx.snap | 479 ---- .../src/app/testQueue/AskOnEntryTag.test.tsx | 2 +- frontend/src/app/testQueue/QueueItem.test.tsx | 125 +- frontend/src/app/testQueue/QueueItem.tsx | 2 - frontend/src/app/testQueue/TestTimer.test.tsx | 32 +- .../__snapshots__/QueueItem.test.tsx.snap | 349 --- .../AddToQueueSearch-add-to-queue.test.tsx | 10 +- .../AddToQueueSearch-patient-search.test.tsx | 35 +- .../addToQueue/SearchResults.test.tsx | 25 +- .../__snapshots__/SearchResults.test.tsx.snap | 133 - .../app/testResults/EmailTestResultModal.tsx | 2 +- .../app/testResults/TestResultInput.test.tsx | 13 +- .../testResults/TestResultPrintModal.test.tsx | 21 +- .../testResults/TestResultTextModal.test.tsx | 18 +- .../app/testResults/TestResultTextModal.tsx | 10 +- .../app/testResults/TestResultsList.test.tsx | 24 +- .../TestResultInput.test.tsx.snap | 215 -- .../TestResultPrintModal.test.tsx.snap | 296 -- frontend/src/patientApp/GuardedRoute.test.tsx | 12 +- .../src/patientApp/PatientHeader.test.tsx | 32 +- .../__snapshots__/PatientHeader.test.tsx.snap | 71 - .../SelfRegistration.test.tsx | 91 +- .../selfRegistration/SelfRegistration.tsx | 1 - .../AoEPatientFormContainer.test.tsx | 12 +- .../timeOfTest/AoEPatientFormContainer.tsx | 6 +- .../src/patientApp/timeOfTest/DOB.test.tsx | 42 +- .../timeOfTest/PatientFormContainer.test.tsx | 17 +- .../timeOfTest/PatientFormContainer.tsx | 4 - .../timeOfTest/PatientProfile.test.tsx | 12 +- .../PatientProfileContainer.test.tsx | 10 +- .../timeOfTest/TermsOfService.test.tsx | 9 +- .../patientApp/timeOfTest/TestResult.test.tsx | 35 +- .../AoEPatientFormContainer.test.tsx.snap | 863 ------ .../PatientFormContainer.test.tsx.snap | 2528 ----------------- .../PatientProfile.test.tsx.snap | 130 - .../PatientProfileContainer.test.tsx.snap | 232 -- .../TermsOfService.test.tsx.snap | 293 -- .../__snapshots__/TestResult.test.tsx.snap | 367 --- frontend/src/setupTests.js | 11 + frontend/yarn.lock | 162 +- 104 files changed, 1623 insertions(+), 9457 deletions(-) delete mode 100644 frontend/src/app/Settings/Users/__snapshots__/ManageUsers.test.tsx.snap delete mode 100644 frontend/src/app/commonComponents/__test__/__snapshots__/ErrorPage.test.tsx.snap delete mode 100644 frontend/src/app/facilitySelect/__snapshots__/FacilitySelect.test.tsx.snap delete mode 100644 frontend/src/app/facilitySelect/__snapshots__/WithFacility.test.tsx.snap delete mode 100644 frontend/src/app/testQueue/AoEForm/__snapshots__/AoEForm.test.tsx.snap delete mode 100644 frontend/src/app/testQueue/AoEForm/__snapshots__/SymptomInputs.test.tsx.snap delete mode 100644 frontend/src/app/testQueue/__snapshots__/QueueItem.test.tsx.snap delete mode 100644 frontend/src/app/testQueue/addToQueue/__snapshots__/SearchResults.test.tsx.snap delete mode 100644 frontend/src/app/testResults/__snapshots__/TestResultInput.test.tsx.snap delete mode 100644 frontend/src/app/testResults/__snapshots__/TestResultPrintModal.test.tsx.snap delete mode 100644 frontend/src/patientApp/__snapshots__/PatientHeader.test.tsx.snap delete mode 100644 frontend/src/patientApp/timeOfTest/__snapshots__/AoEPatientFormContainer.test.tsx.snap delete mode 100644 frontend/src/patientApp/timeOfTest/__snapshots__/PatientFormContainer.test.tsx.snap delete mode 100644 frontend/src/patientApp/timeOfTest/__snapshots__/PatientProfile.test.tsx.snap delete mode 100644 frontend/src/patientApp/timeOfTest/__snapshots__/PatientProfileContainer.test.tsx.snap delete mode 100644 frontend/src/patientApp/timeOfTest/__snapshots__/TermsOfService.test.tsx.snap delete mode 100644 frontend/src/patientApp/timeOfTest/__snapshots__/TestResult.test.tsx.snap diff --git a/backend/build.gradle b/backend/build.gradle index ed844e6a61..29e75e3528 100644 --- a/backend/build.gradle +++ b/backend/build.gradle @@ -175,6 +175,7 @@ sonarqube { // In order to get both the frontend and backend code to report, we need to set the sonar project to the root directory. property "sonar.sources", "backend/src/main/java,frontend/src,ops/services/app_functions/" property "sonar.exclusions", "backend/src/**/*Config*.java,frontend/src/**/*.test.*,frontend/src/stories/**/*,frontend/src/**/*.stories.tsx,frontend/src/generated/*.tsx,ops/services/app_functions/**/*.test.*,ops/services/app_functions/**/*config*" + property "sonar.coverage.exclusions", "frontend/src/setupTests.js" property "sonar.cpd.exclusions", "frontend/src/lang/*.ts" property "sonar.javascript.lcov.reportPaths", "frontend/coverage/lcov.info,ops/services/app_functions/report_stream_batched_publisher/functions/coverage/lcov.info" } diff --git a/frontend/package.json b/frontend/package.json index efea477aa8..b69af365fc 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -103,7 +103,10 @@ "plugin:import/warnings" ], "plugins": [ - "graphql" + "graphql", + "testing-library", + "unused-imports", + "jest-dom" ], "rules": { "graphql/template-strings": [ @@ -124,7 +127,18 @@ } ], "import/newline-after-import": 1, - "import/no-commonjs": 0 + "import/no-commonjs": 0, + "no-unused-vars": "off", + "unused-imports/no-unused-imports": "error", + "unused-imports/no-unused-vars": [ + "warn", + { + "vars": "all", + "varsIgnorePattern": "^_", + "args": "after-used", + "argsIgnorePattern": "^_" + } + ] }, "overrides": [ { @@ -134,6 +148,25 @@ "rules": { "import/no-anonymous-default-export": "off" } + }, + { + "files": [ + "**/__tests__/**/*.[jt]s?(x)", + "**/?(*.)+(spec|test).[jt]s?(x)" + ], + "extends": [ + "plugin:testing-library/react", + "plugin:jest-dom/recommended" + ], + "rules": { + "testing-library/no-render-in-setup": [ + "error", + { + "allowTestingFrameworkSetupHook": "beforeEach" + } + ], + "testing-library/no-node-access": "off" + } } ] }, @@ -169,7 +202,6 @@ "@types/react-dom": "^17.0.0", "@types/react-modal": "^3.10.6", "@types/react-redux": "^7.1.11", - "@types/react-test-renderer": "^17.0.1", "@types/redux-mock-store": "^1.0.2", "@types/smartystreets-javascript-sdk": "^1.6.2", "@types/uuid": "^8.3.0", @@ -181,6 +213,9 @@ "eslint-config-prettier": "^8.3.0", "eslint-plugin-graphql": "^4.0.0", "eslint-plugin-import": "^2.22.1", + "eslint-plugin-jest-dom": "^3.9.2", + "eslint-plugin-testing-library": "^5.0.0", + "eslint-plugin-unused-imports": "1.1.5", "faker": "^5.5.3", "geckodriver": "^1.22.3", "jest-fetch-mock": "^3.0.3", @@ -190,7 +225,6 @@ "nightwatch": "^1.5.1", "npm-run-all": "^4.1.5", "prettier": "^2.2.1", - "react-test-renderer": "^17.0.1", "redux-mock-store": "^1.5.4", "stylelint": "^13.12.0", "stylelint-config-standard": "^21.0.0", @@ -207,4 +241,4 @@ "\\.(css|less|sass|scss)$": "/__mocks__/styleMock.js" } } -} \ No newline at end of file +} diff --git a/frontend/src/app/App.test.tsx b/frontend/src/app/App.test.tsx index 73b60bc0a5..221594649f 100644 --- a/frontend/src/app/App.test.tsx +++ b/frontend/src/app/App.test.tsx @@ -2,7 +2,11 @@ import { BrowserRouter as Router, MemoryRouter, Route } from "react-router-dom"; import { Provider } from "react-redux"; import createMockStore, { MockStoreEnhanced } from "redux-mock-store"; import { MockedProvider, MockedResponse } from "@apollo/client/testing"; -import { render, screen, waitFor } from "@testing-library/react"; +import { + render, + screen, + waitForElementToBeRemoved, +} from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { GetTopLevelDashboardMetricsNewDocument } from "../generated/graphql"; @@ -234,9 +238,10 @@ describe("App", () => { facilityQueryMock, getAnalyticsQueryMock(), ]); - await waitFor(() => { - userEvent.click(screen.getByText("Testing Site", { exact: false })); - }); + await waitForElementToBeRemoved(() => + screen.queryByText("Loading account information...") + ); + userEvent.click(screen.getAllByText("Testing Site", { exact: false })[0]); expect( await screen.findByText("COVID-19 testing data") ).toBeInTheDocument(); @@ -260,9 +265,7 @@ describe("App", () => { exact: false, }); expect(trainingWelcome).toBeInTheDocument(); - await waitFor(() => { - userEvent.click(screen.getByText("Got it", { exact: false })); - }); + userEvent.click(screen.getByText("Got it", { exact: false })); expect(trainingWelcome).not.toBeInTheDocument(); }); it("does not display training notifications outside the training environment", () => { diff --git a/frontend/src/app/Settings/Facility/Components/ManageDevices.test.tsx b/frontend/src/app/Settings/Facility/Components/ManageDevices.test.tsx index bb66266172..70568edcf9 100644 --- a/frontend/src/app/Settings/Facility/Components/ManageDevices.test.tsx +++ b/frontend/src/app/Settings/Facility/Components/ManageDevices.test.tsx @@ -1,11 +1,5 @@ import { useState } from "react"; -import { - fireEvent, - render, - screen, - waitFor, - within, -} from "@testing-library/react"; +import { fireEvent, render, screen, within } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import ManageDevices from "./ManageDevices"; @@ -140,14 +134,14 @@ describe("ManageDevices", () => { it("allows user to change the device type on an existing device", async () => { const [deviceDropdown] = await screen.findAllByRole("combobox"); - await waitFor(() => { - userEvent.selectOptions(deviceDropdown, "device-c"); - }); + userEvent.selectOptions(deviceDropdown, "device-c"); expect( - (screen.getAllByRole("option", { - name: "Device C", - })[0] as HTMLOptionElement).selected + (( + await screen.findAllByRole("option", { + name: "Device C", + }) + )[0] as HTMLOptionElement).selected ).toBeTruthy(); }); @@ -157,14 +151,14 @@ describe("ManageDevices", () => { "combobox" ); - await waitFor(() => { - userEvent.selectOptions(swabDropdown, "fake-specimen-id-2"); - }); + userEvent.selectOptions(swabDropdown, "fake-specimen-id-2"); expect( - (screen.getAllByRole("option", { - name: "Fake Specimen 2", - })[0] as HTMLOptionElement).selected + (( + await screen.findAllByRole("option", { + name: "Fake Specimen 2", + }) + )[0] as HTMLOptionElement).selected ).toBeTruthy(); }); @@ -180,9 +174,7 @@ describe("ManageDevices", () => { expect(dropdowns.length).toBe(4); - await waitFor(() => { - fireEvent.click(screen.getByText("Add device", { exact: false })); - }); + fireEvent.click(screen.getByText("Add device", { exact: false })); const updatedDropdowns = await screen.findAllByRole("combobox"); expect(updatedDropdowns.length).toBe(6); @@ -193,11 +185,9 @@ describe("ManageDevices", () => { expect(dropdowns.length).toBe(4); - await waitFor(() => { - fireEvent.click( - screen.getAllByLabelText("Delete device", { exact: false })[0] - ); - }); + fireEvent.click( + screen.getAllByLabelText("Delete device", { exact: false })[0] + ); const updatedDropdowns = await screen.findAllByRole("combobox"); expect(updatedDropdowns.length).toBe(2); @@ -217,14 +207,14 @@ describe("ManageDevices", () => { ).toBeTruthy(); // Change device to one with _different_ configured swab types - await waitFor(() => { - userEvent.selectOptions(deviceDropdownElement, "device-b"); - }); + userEvent.selectOptions(deviceDropdownElement, "device-b"); expect( - (screen.getAllByRole("option", { - name: "Fake Specimen 1", - })[0] as HTMLOptionElement).selected + (( + await screen.findAllByRole("option", { + name: "Fake Specimen 1", + }) + )[0] as HTMLOptionElement).selected ).toBeTruthy(); }); }); diff --git a/frontend/src/app/Settings/Facility/Components/ManageDevices.tsx b/frontend/src/app/Settings/Facility/Components/ManageDevices.tsx index 6d6c4c545c..61805c262b 100644 --- a/frontend/src/app/Settings/Facility/Components/ManageDevices.tsx +++ b/frontend/src/app/Settings/Facility/Components/ManageDevices.tsx @@ -26,7 +26,6 @@ const ManageDevices: React.FC = ({ updateDefaultDevice, deviceSpecimenTypeOptions, errors, - validateField, }) => { const deviceErrors: React.ReactNode[] = []; if (errors.deviceTypes) { diff --git a/frontend/src/app/Settings/Facility/FacilityFormContainer.test.tsx b/frontend/src/app/Settings/Facility/FacilityFormContainer.test.tsx index 98898393cc..bb84a3edef 100644 --- a/frontend/src/app/Settings/Facility/FacilityFormContainer.test.tsx +++ b/frontend/src/app/Settings/Facility/FacilityFormContainer.test.tsx @@ -1,4 +1,8 @@ -import { render, screen, act } from "@testing-library/react"; +import { + render, + screen, + waitForElementToBeRemoved, +} from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { MockedProvider } from "@apollo/client/testing"; import { Provider } from "react-redux"; @@ -232,20 +236,14 @@ describe("FacilityFormContainer", () => { }); it("redirects on successful save", async () => { - await act(async () => { - await new Promise((resolve) => setTimeout(resolve, 0)); - await userEvent.click(screen.getByRole("button")); - await new Promise((resolve) => setTimeout(resolve, 0)); - expect(await screen.findByText("Redirected")).toBeDefined(); - }); + await waitForElementToBeRemoved(() => screen.queryByText("Loading...")); + userEvent.click(screen.getByRole("button")); + expect(await screen.findByText("Redirected")).toBeInTheDocument(); }); it("tracks custom telemetry event on successful save", async () => { - await act(async () => { - await new Promise((resolve) => setTimeout(resolve, 0)); - await userEvent.click(screen.getByRole("button")); - await new Promise((resolve) => setTimeout(resolve, 0)); - expect(trackEventMock).toBeCalledWith({ name: "Save Settings" }); - }); + await waitForElementToBeRemoved(() => screen.queryByText("Loading...")); + userEvent.click(screen.getByRole("button")); + expect(trackEventMock).toBeCalledWith({ name: "Save Settings" }); }); }); diff --git a/frontend/src/app/Settings/FacilityForm.test.tsx b/frontend/src/app/Settings/FacilityForm.test.tsx index 1fb7875067..4c0af9021e 100644 --- a/frontend/src/app/Settings/FacilityForm.test.tsx +++ b/frontend/src/app/Settings/FacilityForm.test.tsx @@ -160,10 +160,9 @@ describe("FacilityForm", () => { const facilityNameInput = screen.getByLabelText("Testing facility name", { exact: false, }); - await waitFor(() => { - userEvent.clear(facilityNameInput); - userEvent.click(saveButton); - }); + userEvent.clear(facilityNameInput); + userEvent.click(saveButton); + await waitFor(async () => expect(saveButton).toBeEnabled()); expect(saveFacility).toBeCalledTimes(0); }); it("validates optional email field", async () => { @@ -189,15 +188,12 @@ describe("FacilityForm", () => { }) ).toBeInTheDocument(); - await waitFor(async () => { - userEvent.click(saveButton); - }); + userEvent.click(saveButton); expect(saveFacility).toBeCalledTimes(0); userEvent.type(emailInput, "foofacility@example.com"); - await waitFor(async () => { - userEvent.click(saveButton); - }); + userEvent.click(saveButton); + await waitFor(async () => expect(saveButton).toBeEnabled()); await validateAddress(saveFacility); }); it("only accepts live jurisdictions", async () => { @@ -262,9 +258,8 @@ describe("FacilityForm", () => { ).toBeInTheDocument(); const saveButton = screen.getAllByText("Save changes")[0]; - await waitFor(async () => { - userEvent.click(saveButton); - }); + userEvent.click(saveButton); + await waitFor(async () => expect(saveButton).toBeEnabled()); expect(saveFacility).toBeCalledTimes(0); }); }); @@ -374,9 +369,8 @@ describe("FacilityForm", () => { ).toBeInTheDocument(); const saveButton = screen.getAllByText("Save changes")[0]; - await waitFor(async () => { - userEvent.click(saveButton); - }); + userEvent.click(saveButton); + await waitFor(async () => expect(saveButton).toBeEnabled()); expect(saveFacility).toBeCalledTimes(0); }); @@ -480,9 +474,8 @@ describe("FacilityForm", () => { ).toBeInTheDocument(); const saveButton = screen.getAllByText("Save changes")[0]; - await waitFor(async () => { - userEvent.click(saveButton); - }); + userEvent.click(saveButton); + await waitFor(async () => expect(saveButton).toBeEnabled()); expect(saveFacility).toBeCalledTimes(0); }); }); @@ -579,12 +572,11 @@ describe("FacilityForm", () => { ); // Delete default device const deleteButtons = await screen.findAllByLabelText("Delete device"); - await waitFor(() => { - userEvent.click(deleteButtons[0]); - }); + userEvent.click(deleteButtons[0]); // Attempt save const saveButtons = await screen.findAllByText("Save changes"); userEvent.click(saveButtons[0]); + await waitFor(async () => expect(saveButtons[0]).toBeEnabled()); const warning = await screen.findByText( "A default device must be selected", { exact: false } @@ -616,10 +608,7 @@ describe("FacilityForm", () => { "device-dropdown-0" ) as HTMLSelectElement; - await waitFor(() => { - userEvent.selectOptions(dropdown, unusedDevice.internalId); - }); - + userEvent.selectOptions(dropdown, unusedDevice.internalId); expect( (screen.getAllByRole("option", { name: unusedDevice.name, @@ -633,9 +622,8 @@ describe("FacilityForm", () => { // Attempt save const saveButtons = await screen.findAllByText("Save changes"); - await waitFor(async () => { - userEvent.click(saveButtons[0]); - }); + userEvent.click(saveButtons[0]); + await waitFor(async () => expect(saveButtons[0]).toBeEnabled()); const warning = await screen.findByText( "A default device must be selected", { exact: false } @@ -654,7 +642,7 @@ async function validateAddress( const radios = screen.getAllByLabelText(selection, { exact: false }); radios.forEach((r) => userEvent.click(r)); const button = screen.getAllByText("Save changes")[2]; - expect(button).not.toBeDisabled(); + expect(button).toBeEnabled(); userEvent.click(button); expect(saveFacility).toBeCalledTimes(1); } diff --git a/frontend/src/app/Settings/ManageOrganization.test.tsx b/frontend/src/app/Settings/ManageOrganization.test.tsx index 3eef28f54f..0ca754ce3e 100644 --- a/frontend/src/app/Settings/ManageOrganization.test.tsx +++ b/frontend/src/app/Settings/ManageOrganization.test.tsx @@ -1,5 +1,5 @@ import { MockedProvider } from "@apollo/client/testing"; -import { render, screen, waitFor } from "@testing-library/react"; +import { render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { Provider } from "react-redux"; import { DeepPartial } from "redux"; @@ -48,13 +48,11 @@ describe("ManageOrganization", () => { exact: false, }); const saveButton = screen.getByText("Save settings"); - expect(orgNameInput).not.toBeDisabled(); + expect(orgNameInput).toBeEnabled(); userEvent.type(orgNameInput, "Penny Lane"); userEvent.selectOptions(orgTypeInput, "other"); - expect(saveButton).not.toBeDisabled(); - await waitFor(() => { - userEvent.click(saveButton); - }); + expect(saveButton).toBeEnabled(); + userEvent.click(saveButton); }); it("allows org type change for regular admins", async () => { @@ -71,10 +69,8 @@ describe("ManageOrganization", () => { }); const saveButton = screen.getByText("Save settings"); userEvent.selectOptions(orgTypeInput, "hospice"); - expect(saveButton).not.toBeDisabled(); - await waitFor(() => { - userEvent.click(saveButton); - }); + expect(saveButton).toBeEnabled(); + userEvent.click(saveButton); }); }); diff --git a/frontend/src/app/Settings/ManageSelfRegistrationLinks.test.tsx b/frontend/src/app/Settings/ManageSelfRegistrationLinks.test.tsx index b7c623ef44..2cebbb878b 100644 --- a/frontend/src/app/Settings/ManageSelfRegistrationLinks.test.tsx +++ b/frontend/src/app/Settings/ManageSelfRegistrationLinks.test.tsx @@ -63,18 +63,16 @@ describe("ManageSelfRegistrationLinks", () => { it("copies the org link", async () => { const orgUrl = `${process.env.REACT_APP_BASE_URL}/register/${expectedOrgSlug}`; const [orgBtn] = screen.getAllByRole("button"); - await waitFor(() => { - userEvent.click(orgBtn); - }); + userEvent.click(orgBtn); + await waitFor(async () => expect(orgBtn).toBeEnabled()); expect(navigator.clipboard.writeText).toBeCalledWith(orgUrl); }); it("copies a facility link", async () => { const facilityUrl = `${process.env.REACT_APP_BASE_URL}/register/${expectedFacilitySlug}`; const btns = screen.getAllByRole("button"); - await waitFor(() => { - userEvent.click(btns[2]); - }); + userEvent.click(btns[2]); + await waitFor(async () => expect(btns[2]).toBeEnabled()); expect(navigator.clipboard.writeText).toBeCalledWith(facilityUrl); }); }); diff --git a/frontend/src/app/Settings/Users/ManageUsers.test.tsx b/frontend/src/app/Settings/Users/ManageUsers.test.tsx index e8af63b913..9092c19c0f 100644 --- a/frontend/src/app/Settings/Users/ManageUsers.test.tsx +++ b/frontend/src/app/Settings/Users/ManageUsers.test.tsx @@ -1,5 +1,11 @@ import { MockedProvider } from "@apollo/client/testing"; -import { render, fireEvent, waitFor, screen } from "@testing-library/react"; +import { + render, + fireEvent, + waitFor, + screen, + waitForElementToBeRemoved, +} from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { Provider } from "react-redux"; import { MemoryRouter } from "react-router-dom"; @@ -272,60 +278,41 @@ describe("ManageUsers", () => { }); describe("regular list of users", () => { - let container: any, - findByText: any, - findAllByRole: any, - getByText: any, - getByLabelText: any; beforeEach(async () => { - await waitFor(() => { - const { - container: ui, - findByText: findText, - findAllByRole: findAllRole, - getByText: getText, - getByLabelText: getLabelText, - } = render( - - - - ); - container = ui; - findByText = findText; - findAllByRole = findAllRole; - getByText = getText; - getByLabelText = getLabelText; - }); - }); - - it("displays the list of users and defaults to the first user", async () => { - expect(container).toMatchSnapshot(); + render( + + + + ); + await waitForElementToBeRemoved(() => screen.queryByText("?, ?")); }); it("disables logged-in user's settings", async () => { - userEvent.click(getByText(displayFullName("Bob", "", "Bobberoo"))); - await findByText("YOU"); - expect(getByLabelText("admin", { exact: false })).toHaveAttribute( - "disabled" - ); - expect(getByLabelText("user", { exact: false })).toHaveAttribute( - "disabled" - ); - expect(getByLabelText("Testing only", { exact: false })).toHaveAttribute( - "disabled" - ); - expect(container).toMatchSnapshot(); + const nameButton = screen.getByRole("tab", { + name: displayFullName("Bob", "", "Bobberoo"), + }); + userEvent.click(nameButton); + await waitFor(() => { + expect(screen.getByText("YOU")).toBeInTheDocument(); + }); + expect( + screen.getByLabelText("Admin (full access)", { exact: false }) + ).toBeDisabled(); + expect(screen.getByLabelText("user", { exact: false })).toBeDisabled(); + expect( + screen.getByLabelText("Testing only", { exact: false }) + ).toBeDisabled(); }); it("passes user details to the addUserToOrg function", async () => { @@ -336,18 +323,16 @@ describe("ManageUsers", () => { role: "USER", }; - userEvent.click(getByText("New User", { exact: false })); - const [first, last, email] = await findAllByRole("textbox"); - const select = getByLabelText("Access level", { exact: false }); + userEvent.click(screen.getByText("New User", { exact: false })); + const [first, last, email] = await screen.findAllByRole("textbox"); + const select = screen.getByLabelText("Access level", { exact: false }); fireEvent.change(first, inputValue(newUser.firstName)); fireEvent.change(last, inputValue(newUser.lastName)); fireEvent.change(email, inputValue(newUser.email)); fireEvent.change(select, inputValue(newUser.role)); - const sendButton = getByText("Send invite"); - await waitFor(() => { - userEvent.click(screen.getAllByRole("checkbox")[1]); - expect(sendButton).not.toBeDisabled(); - }); + const sendButton = screen.getByText("Send invite"); + userEvent.click(screen.getAllByRole("checkbox")[1]); + expect(sendButton).toBeEnabled(); userEvent.click(sendButton); await waitFor(() => expect(addUserToOrg).toBeCalled()); expect(addUserToOrg).toBeCalledWith({ variables: newUser }); @@ -369,18 +354,16 @@ describe("ManageUsers", () => { role: "USER", }; - userEvent.click(getByText("New User", { exact: false })); - const [first, last, email] = await findAllByRole("textbox"); - const select = getByLabelText("Access level", { exact: false }); + userEvent.click(screen.getByText("New User", { exact: false })); + const [first, last, email] = await screen.findAllByRole("textbox"); + const select = screen.getByLabelText("Access level", { exact: false }); fireEvent.change(first, inputValue(newUser.firstName)); fireEvent.change(last, inputValue(newUser.lastName)); fireEvent.change(email, inputValue(newUser.email)); fireEvent.change(select, inputValue(newUser.role)); - const sendButton = getByText("Send invite"); - await waitFor(() => { - userEvent.click(screen.getAllByRole("checkbox")[1]); - expect(sendButton).not.toBeDisabled(); - }); + const sendButton = screen.getByText("Send invite"); + userEvent.click(screen.getAllByRole("checkbox")[1]); + expect(sendButton).toBeEnabled(); userEvent.click(sendButton); await waitFor(() => expect(addUserToOrg).not.toBeCalled()); expect( @@ -395,14 +378,14 @@ describe("ManageUsers", () => { email: "jane@smith.co", }; - userEvent.click(getByText("New User", { exact: false })); - const [first, last, email] = await findAllByRole("textbox"); + userEvent.click(screen.getByText("New User", { exact: false })); + const [first, last, email] = await screen.findAllByRole("textbox"); fireEvent.change(first, inputValue(newUser.firstName)); fireEvent.change(last, inputValue(newUser.lastName)); fireEvent.change(email, inputValue(newUser.email)); userEvent.click(screen.getAllByRole("checkbox")[1]); - const sendButton = getByText("Send invite"); - await waitFor(() => expect(sendButton).not.toBeDisabled()); + const sendButton = screen.getByText("Send invite"); + await waitFor(() => expect(sendButton).toBeEnabled()); userEvent.click(sendButton); await waitFor(() => expect(addUserToOrg).toBeCalled()); expect(addUserToOrg).toBeCalledWith({ @@ -411,9 +394,9 @@ describe("ManageUsers", () => { }); it("deletes a user", async () => { - const removeButton = await findByText("Remove", { exact: false }); + const removeButton = await screen.findByText("Remove", { exact: false }); userEvent.click(removeButton); - const sureButton = await findByText("Yes", { exact: false }); + const sureButton = await screen.findByText("Yes", { exact: false }); userEvent.click(sureButton); await waitFor(() => expect(deleteUser).toBeCalled()); expect(deleteUser).toBeCalledWith({ @@ -422,10 +405,10 @@ describe("ManageUsers", () => { }); it("updates someone from user to admin", async () => { - const [adminOption] = await findAllByRole("radio"); + const [adminOption] = await screen.findAllByRole("radio"); userEvent.click(adminOption); - const button = await findByText("Save", { exact: false }); - await waitFor(() => expect(button).not.toHaveAttribute("disabled")); + const button = await screen.findByText("Save", { exact: false }); + await waitFor(() => expect(button).toBeEnabled()); userEvent.click(button); await waitFor(() => expect(updateUserPrivileges).toBeCalled()); expect(updateUserPrivileges).toBeCalledWith({ @@ -441,17 +424,14 @@ describe("ManageUsers", () => { it("adds adds a facility for a user", async () => { const facilitySelect = await screen.findByLabelText("Add facility"); const addButton = screen.getByText("Add"); - await waitFor(() => { - fireEvent.change(facilitySelect, { target: { value: "a1" } }); - expect(addButton).not.toBeDisabled(); - }); + userEvent.selectOptions(facilitySelect, ["a1"]); + expect(addButton).toBeEnabled(); userEvent.click(addButton); const saveButton = screen.getByText("Save changes"); - await waitFor(() => expect(saveButton).not.toBeDisabled()); - await waitFor(() => { - userEvent.click(saveButton); - expect(updateUserPrivileges).toBeCalled(); - }); + await waitFor(() => expect(saveButton).toBeEnabled()); + userEvent.click(saveButton); + await waitForElementToBeRemoved(() => screen.queryByText("Saving...")); + expect(updateUserPrivileges).toBeCalled(); expect(updateUserPrivileges).toBeCalledWith({ variables: { accessAllFacilities: false, @@ -463,9 +443,9 @@ describe("ManageUsers", () => { }); it("resets a user's password", async () => { - const resetButton = await findByText("Reset", { exact: false }); + const resetButton = await screen.findByText("Reset", { exact: false }); userEvent.click(resetButton); - const sureButton = await findByText("Yes", { exact: false }); + const sureButton = await screen.findByText("Yes", { exact: false }); userEvent.click(sureButton); await waitFor(() => expect(resetUserPassword).toBeCalled()); expect(resetUserPassword).toBeCalledWith({ @@ -475,37 +455,28 @@ describe("ManageUsers", () => { }); describe("empty list of users", () => { - let findByText: any, findAllByRole: any, getByText: any; beforeEach(async () => { - await waitFor(() => { - const { - findByText: findText, - findAllByRole: findAllRole, - getByText: getText, - } = render( - - Promise.resolve()} - resendUserActivationEmail={resendUserActivationEmail} - /> - - ); - findByText = findText; - findAllByRole = findAllRole; - getByText = getText; - }); + render( + + Promise.resolve()} + resendUserActivationEmail={resendUserActivationEmail} + /> + + ); + await screen.findByText("New User", { exact: false }); }); it("fails gracefully when there are no users", async () => { - const noUsers = await findByText("no users", { exact: false }); + const noUsers = await screen.findByText("no users", { exact: false }); expect(noUsers).toBeInTheDocument(); }); @@ -516,18 +487,17 @@ describe("ManageUsers", () => { email: "jane@smith.co", }; - userEvent.click(getByText("New User", { exact: false })); - const [first, last, email] = await findAllByRole("textbox"); - fireEvent.change(first, inputValue(newUser.firstName)); - fireEvent.change(last, inputValue(newUser.lastName)); - fireEvent.change(email, inputValue(newUser.email)); + userEvent.click(screen.getByText("New User", { exact: false })); + const [first, last, email] = await screen.findAllByRole("textbox"); + userEvent.type(first, newUser.firstName); + userEvent.type(last, newUser.lastName); + userEvent.type(email, newUser.email); userEvent.click(screen.getByRole("checkbox")); - const sendButton = getByText("Send invite"); - await waitFor(() => expect(sendButton).not.toBeDisabled()); - await waitFor(() => { - userEvent.click(sendButton); - expect(addUserToOrg).toBeCalled(); - }); + const sendButton = screen.getByText("Send invite"); + await waitFor(() => expect(sendButton).toBeEnabled()); + userEvent.click(sendButton); + await waitForElementToBeRemoved(() => screen.queryByText("Sending")); + await waitFor(() => expect(addUserToOrg).toBeCalled()); expect(addUserToOrg).toBeCalledWith({ variables: { ...newUser, role: "USER" }, }); @@ -535,33 +505,32 @@ describe("ManageUsers", () => { }); describe("suspended users", () => { - let findByText: any; beforeEach(async () => { - await waitFor(() => { - const { findByText: findText } = render( - - Promise.resolve()} - resendUserActivationEmail={resendUserActivationEmail} - /> - - ); - findByText = findText; - }); + render( + + Promise.resolve()} + resendUserActivationEmail={resendUserActivationEmail} + /> + + ); + await screen.findByText("New User", { exact: false }); }); it("reactivates a suspended user", async () => { - const reactivateButton = await findByText("Reactivate", { exact: false }); + const reactivateButton = await screen.findByText("Reactivate", { + exact: false, + }); userEvent.click(reactivateButton); - const sureButton = await findByText("Yes", { exact: false }); + const sureButton = await screen.findByText("Yes", { exact: false }); userEvent.click(sureButton); await waitFor(() => expect(reactivateUser).toBeCalled()); expect(reactivateUser).toBeCalledWith({ @@ -577,33 +546,30 @@ describe("ManageUsers", () => { }); describe("pending account setup users", () => { - let findByText: any; beforeEach(async () => { - await waitFor(() => { - const { findByText: findText } = render( - - Promise.resolve()} - resendUserActivationEmail={resendUserActivationEmail} - /> - - ); - findByText = findText; - }); + render( + + Promise.resolve()} + resendUserActivationEmail={resendUserActivationEmail} + /> + + ); + await screen.findByText("New User", { exact: false }); }); it("resends account activation email for pending user", async () => { - const resendButton = await findByText("Resend", { exact: false }); + const resendButton = await screen.findByText("Resend", { exact: false }); userEvent.click(resendButton); - const sureButton = await findByText("Yes", { exact: false }); + const sureButton = await screen.findByText("Yes", { exact: false }); userEvent.click(sureButton); await waitFor(() => expect(resendUserActivationEmail).toBeCalled()); expect(resendUserActivationEmail).toBeCalledWith({ @@ -671,28 +637,26 @@ describe("ManageUsers", () => { }, }, ]; - await waitFor(() => { - render( - - - - Promise.resolve()} - resendUserActivationEmail={resendUserActivationEmail} - /> - - - - ); - }); + render( + + + + Promise.resolve()} + resendUserActivationEmail={resendUserActivationEmail} + /> + + + + ); const removeButton = ( await screen.findAllByLabelText("Remove facility", { @@ -700,13 +664,10 @@ describe("ManageUsers", () => { }) )[0]; const saveButton = await screen.findByText("Save changes"); - await waitFor(() => { - userEvent.click(removeButton); - expect(saveButton).not.toBeDisabled(); - }); - await waitFor(() => { - userEvent.click(saveButton); - }); + userEvent.click(removeButton); + expect(saveButton).toBeEnabled(); + userEvent.click(saveButton); + await waitForElementToBeRemoved(() => screen.queryByText("Saving...")); expect(updateUserPrivileges).toBeCalledWith({ variables: { accessAllFacilities: false, diff --git a/frontend/src/app/Settings/Users/UsersSideNav.tsx b/frontend/src/app/Settings/Users/UsersSideNav.tsx index 4d3ed79d4c..04630fbdc7 100644 --- a/frontend/src/app/Settings/Users/UsersSideNav.tsx +++ b/frontend/src/app/Settings/Users/UsersSideNav.tsx @@ -33,6 +33,7 @@ const UsersSideNav: React.FC = ({ key={user.id} > - -
-
-
-

- Users -

-
    -
  • - -
  • -
  • - -
  • -
-
-
-
-
-

- Bobberoo, Bob -

-
- - Unknown - -
-
- - YOU - -
-
-

- User roles -

-

- Admins have full access to SimpleReport. They can conduct tests, manage test results and patient profiles, and also manage account settings, users, and testing facilities. Standard and testing only users have limited access for specific tasks, as described below. -

-
-
- - Roles - -
-
- - -
-
- - -
-
- - -
-
-
-
-

- Facility access - -

-

- Admins have access to all facilities -

-
-
- - Access all facilities - -
-
- - -
-
-
-
- - - - - - - - - - - -
- Bar Org - - -
- Foo Org - - -
-
- -
-
-
- - -`; - -exports[`ManageUsers regular list of users displays the list of users and defaults to the first user 1`] = ` -
-
-
-

- Manage users -

- -
-
-
-
-

- Users -

-
    -
  • - -
  • -
  • - -
  • -
-
-
-
-
-

- Arthur, John -

-
- - Unknown - -
-
- -
-
-

- User roles -

-

- Admins have full access to SimpleReport. They can conduct tests, manage test results and patient profiles, and also manage account settings, users, and testing facilities. Standard and testing only users have limited access for specific tasks, as described below. -

-
-
- - Roles - -
-
- - -
-
- - -
-
- - -
-
-
-
-

- Facility access - -

-

- All users must have access to at least one facility -

-
-
- - Access all facilities - -
-
- - -
-
-
-
- - - - - - -
- Please add at least one facility -
-
-
- -
- -
-
- -
-
- -
-
-
-
-
-`; diff --git a/frontend/src/app/accountCreation/MfaEmailVerify/MfaEmailVerify.test.tsx b/frontend/src/app/accountCreation/MfaEmailVerify/MfaEmailVerify.test.tsx index fee2cc5609..9371d7a57e 100644 --- a/frontend/src/app/accountCreation/MfaEmailVerify/MfaEmailVerify.test.tsx +++ b/frontend/src/app/accountCreation/MfaEmailVerify/MfaEmailVerify.test.tsx @@ -1,6 +1,9 @@ -import { render, screen } from "@testing-library/react"; +import { + render, + screen, + waitForElementToBeRemoved, +} from "@testing-library/react"; import userEvent from "@testing-library/user-event"; -import { act } from "react-dom/test-utils"; import { MemoryRouter, Route, Switch } from "react-router"; import { MfaComplete } from "../MfaComplete/MfaComplete"; @@ -50,9 +53,10 @@ describe("Verify Email MFA", () => { screen.getByLabelText("One-time security code", { exact: false }), "123456" ); - await act(async () => { - await userEvent.click(screen.getByText("Submit")); - }); + userEvent.click(screen.getByText("Submit")); + await waitForElementToBeRemoved(() => + screen.queryByText("Verifying security code …") + ); expect( screen.queryByText("Enter your security code") ).not.toBeInTheDocument(); @@ -74,9 +78,10 @@ describe("Verify Email MFA", () => { screen.getByLabelText("One-time security code", { exact: false }), "999999" ); - await act(async () => { - await userEvent.click(screen.getByText("Submit")); - }); + userEvent.click(screen.getByText("Submit")); + await waitForElementToBeRemoved(() => + screen.queryByText("Verifying security code …") + ); expect(screen.getByText("incorrect code")).toBeInTheDocument(); expect( screen.queryByText( diff --git a/frontend/src/app/accountCreation/MfaGoogleAuthVerify/MfaGoogleAuthVerify.test.tsx b/frontend/src/app/accountCreation/MfaGoogleAuthVerify/MfaGoogleAuthVerify.test.tsx index 88c5191073..e0ca53652b 100644 --- a/frontend/src/app/accountCreation/MfaGoogleAuthVerify/MfaGoogleAuthVerify.test.tsx +++ b/frontend/src/app/accountCreation/MfaGoogleAuthVerify/MfaGoogleAuthVerify.test.tsx @@ -1,6 +1,9 @@ -import { render, screen } from "@testing-library/react"; +import { + render, + screen, + waitForElementToBeRemoved, +} from "@testing-library/react"; import userEvent from "@testing-library/user-event"; -import { act } from "react-dom/test-utils"; import { MemoryRouter, Route, Switch } from "react-router"; import { MfaComplete } from "../MfaComplete/MfaComplete"; @@ -57,9 +60,10 @@ describe("Verify Google Auth MFA", () => { screen.getByLabelText("One-time security code", { exact: false }), "123456" ); - await act(async () => { - await userEvent.click(screen.getByText("Submit")); - }); + userEvent.click(screen.getByText("Submit")); + await waitForElementToBeRemoved(() => + screen.queryByText("Verifying security code …") + ); expect( screen.queryByText("Enter your security code") ).not.toBeInTheDocument(); @@ -80,9 +84,10 @@ describe("Verify Google Auth MFA", () => { screen.getByLabelText("One-time security code", { exact: false }), "999999" ); - await act(async () => { - await userEvent.click(screen.getByText("Submit")); - }); + userEvent.click(screen.getByText("Submit")); + await waitForElementToBeRemoved(() => + screen.queryByText("Verifying security code …") + ); expect(screen.getByText("incorrect code")).toBeInTheDocument(); expect( screen.queryByText( diff --git a/frontend/src/app/accountCreation/MfaOktaVerify/MfaOktaVerify.test.tsx b/frontend/src/app/accountCreation/MfaOktaVerify/MfaOktaVerify.test.tsx index 68f80edc73..586ac3128d 100644 --- a/frontend/src/app/accountCreation/MfaOktaVerify/MfaOktaVerify.test.tsx +++ b/frontend/src/app/accountCreation/MfaOktaVerify/MfaOktaVerify.test.tsx @@ -1,6 +1,9 @@ -import { render, screen } from "@testing-library/react"; +import { + render, + screen, + waitForElementToBeRemoved, +} from "@testing-library/react"; import userEvent from "@testing-library/user-event"; -import { act } from "react-dom/test-utils"; import { MemoryRouter, Route, Switch } from "react-router"; import { MfaComplete } from "../MfaComplete/MfaComplete"; @@ -54,9 +57,10 @@ describe("Verify Okta MFA", () => { screen.getByLabelText("One-time security code", { exact: false }), "123456" ); - await act(async () => { - await userEvent.click(screen.getByText("Submit")); - }); + userEvent.click(screen.getByText("Submit")); + await waitForElementToBeRemoved(() => + screen.queryByText("Verifying security code …") + ); expect( screen.queryByText("Enter your security code") ).not.toBeInTheDocument(); @@ -77,9 +81,10 @@ describe("Verify Okta MFA", () => { screen.getByLabelText("One-time security code", { exact: false }), "999999" ); - await act(async () => { - await userEvent.click(screen.getByText("Submit")); - }); + userEvent.click(screen.getByText("Submit")); + await waitForElementToBeRemoved(() => + screen.queryByText("Verifying security code …") + ); expect(screen.getByText("incorrect code")).toBeInTheDocument(); expect( screen.queryByText( diff --git a/frontend/src/app/accountCreation/MfaPhone/MfaPhone.test.tsx b/frontend/src/app/accountCreation/MfaPhone/MfaPhone.test.tsx index 21bc782930..10ca11250d 100644 --- a/frontend/src/app/accountCreation/MfaPhone/MfaPhone.test.tsx +++ b/frontend/src/app/accountCreation/MfaPhone/MfaPhone.test.tsx @@ -1,21 +1,52 @@ -import { render, screen, waitFor } from "@testing-library/react"; +import { + render, + screen, + waitForElementToBeRemoved, +} from "@testing-library/react"; import userEvent from "@testing-library/user-event"; +import { MemoryRouter, Route, Switch } from "react-router"; + +import { MfaPhoneVerify } from "../MfaPhoneVerify/MfaPhoneVerify"; import { MfaPhone } from "./MfaPhone"; +jest.mock("../AccountCreationApiService", () => ({ + AccountCreationApi: { + enrollVoiceCallMfa: () => { + return new Promise((res) => { + res(true); + }); + }, + }, +})); + describe("Phone call MFA", () => { beforeEach(() => { - render(); + render( + + + + + + + ); }); it("can enter a valid phone number", async () => { - await waitFor(() => { - userEvent.type( - screen.getByLabelText("Phone number", { exact: false }), - "(910) 867-5309" - ); - userEvent.click(screen.getByText("Send code")); - }); + userEvent.type( + screen.getByLabelText("Phone number", { exact: false }), + "(910) 867-5309" + ); + userEvent.click(screen.getByText("Send code")); + await waitForElementToBeRemoved(() => + screen.queryByText("Validating phone number …") + ); expect( screen.queryByText("Phone number is invalid") diff --git a/frontend/src/app/accountCreation/MfaPhoneVerify/MfaPhoneVerify.test.tsx b/frontend/src/app/accountCreation/MfaPhoneVerify/MfaPhoneVerify.test.tsx index 414abfb80f..d87fc92ba8 100644 --- a/frontend/src/app/accountCreation/MfaPhoneVerify/MfaPhoneVerify.test.tsx +++ b/frontend/src/app/accountCreation/MfaPhoneVerify/MfaPhoneVerify.test.tsx @@ -1,6 +1,9 @@ -import { render, screen } from "@testing-library/react"; +import { + render, + screen, + waitForElementToBeRemoved, +} from "@testing-library/react"; import userEvent from "@testing-library/user-event"; -import { act } from "react-dom/test-utils"; import { MemoryRouter, Route, Switch } from "react-router"; import { MfaComplete } from "../MfaComplete/MfaComplete"; @@ -53,9 +56,10 @@ describe("Verify Phone MFA", () => { screen.getByLabelText("One-time security code", { exact: false }), "123456" ); - await act(async () => { - await userEvent.click(screen.getByText("Submit")); - }); + userEvent.click(screen.getByText("Submit")); + await waitForElementToBeRemoved(() => + screen.queryByText("Verifying security code …") + ); expect( screen.queryByText("Enter your security code") ).not.toBeInTheDocument(); @@ -74,9 +78,10 @@ describe("Verify Phone MFA", () => { screen.getByLabelText("One-time security code", { exact: false }), "999999" ); - await act(async () => { - await userEvent.click(screen.getByText("Submit")); - }); + userEvent.click(screen.getByText("Submit")); + await waitForElementToBeRemoved(() => + screen.queryByText("Verifying security code …") + ); expect(screen.getByText("incorrect code")).toBeInTheDocument(); expect( screen.queryByText( diff --git a/frontend/src/app/accountCreation/MfaSecurityKey/MfaSecurityKey.test.tsx b/frontend/src/app/accountCreation/MfaSecurityKey/MfaSecurityKey.test.tsx index 898b6f71e7..7f4549b2f6 100644 --- a/frontend/src/app/accountCreation/MfaSecurityKey/MfaSecurityKey.test.tsx +++ b/frontend/src/app/accountCreation/MfaSecurityKey/MfaSecurityKey.test.tsx @@ -1,4 +1,4 @@ -import { render, screen, act } from "@testing-library/react"; +import { render, screen } from "@testing-library/react"; import { MemoryRouter, Route } from "react-router"; import { MfaComplete } from "../MfaComplete/MfaComplete"; @@ -25,15 +25,15 @@ jest.mock("../AccountCreationApiService", () => ({ })); jest.mock("../../utils/text", () => ({ - strToBin: (str: string) => { + strToBin: (_str: string) => { return Uint8Array.of(8).fill(2); }, - binToStr: (bin: ArrayBuffer) => { + binToStr: (_bin: ArrayBuffer) => { return "str"; }, })); -function create(obj: any) { +function create(_obj: any) { return new Promise((cred) => { cred({ response: { @@ -57,14 +57,12 @@ describe("MFA Security Key Successful", () => { // in the real flow, a user has to touch their security key to trigger the enrollment. // it's not possible to mock that, so instead we mock out functions as if the user // had touched their key and assert that they get to the success page. - act(() => { - render( - - - - - ); - }); + render( + + + + + ); expect( await screen.findByText("Account set up complete") diff --git a/frontend/src/app/accountCreation/MfaSelect/MfaSelect.test.tsx b/frontend/src/app/accountCreation/MfaSelect/MfaSelect.test.tsx index ff530c62a1..c197755149 100644 --- a/frontend/src/app/accountCreation/MfaSelect/MfaSelect.test.tsx +++ b/frontend/src/app/accountCreation/MfaSelect/MfaSelect.test.tsx @@ -1,4 +1,4 @@ -import { render, screen, waitFor } from "@testing-library/react"; +import { render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { MemoryRouter, Route, Switch } from "react-router"; @@ -54,7 +54,7 @@ describe("MfaSelect", () => { }); }); -function create(obj: any) { +function create(_obj: any) { return new Promise((cred) => { cred({ response: { @@ -139,11 +139,9 @@ describe("MfaSelect routing", () => { } ); - await waitFor(() => { - userEvent.click(securityKeyRadio); - expect(securityKeyRadio).toBeChecked(); - userEvent.click(continueButton); - }); + userEvent.click(securityKeyRadio); + expect(securityKeyRadio).toBeChecked(); + userEvent.click(continueButton); expect( screen.getByText( diff --git a/frontend/src/app/accountCreation/MfaSms/MfaSms.test.tsx b/frontend/src/app/accountCreation/MfaSms/MfaSms.test.tsx index ea98b7fc08..6074309e87 100644 --- a/frontend/src/app/accountCreation/MfaSms/MfaSms.test.tsx +++ b/frontend/src/app/accountCreation/MfaSms/MfaSms.test.tsx @@ -1,21 +1,52 @@ -import { render, screen, waitFor } from "@testing-library/react"; +import { + render, + screen, + waitForElementToBeRemoved, +} from "@testing-library/react"; import userEvent from "@testing-library/user-event"; +import { MemoryRouter, Route, Switch } from "react-router"; + +import { MfaSmsVerify } from "../MfaSmsVerify/MfaSmsVerify"; import { MfaSms } from "./MfaSms"; +jest.mock("../AccountCreationApiService", () => ({ + AccountCreationApi: { + enrollSmsMfa: () => { + return new Promise((res) => { + res(true); + }); + }, + }, +})); + describe("SMS MFA", () => { beforeEach(() => { - render(); + render( + + + + + + + ); }); it("can enter a valid phone number", async () => { - await waitFor(() => { - userEvent.type( - screen.getByLabelText("Phone number", { exact: false }), - "(910) 867-5309" - ); - userEvent.click(screen.getByText("Send code")); - }); + userEvent.type( + screen.getByLabelText("Phone number", { exact: false }), + "(910) 867-5309" + ); + userEvent.click(screen.getByText("Send code")); + await waitForElementToBeRemoved(() => + screen.queryByText("Validating phone number …") + ); expect( screen.queryByText("Phone number is invalid") diff --git a/frontend/src/app/accountCreation/MfaSmsVerify/MfaSmsVerify.test.tsx b/frontend/src/app/accountCreation/MfaSmsVerify/MfaSmsVerify.test.tsx index c9e3892e2a..d52f58d313 100644 --- a/frontend/src/app/accountCreation/MfaSmsVerify/MfaSmsVerify.test.tsx +++ b/frontend/src/app/accountCreation/MfaSmsVerify/MfaSmsVerify.test.tsx @@ -1,6 +1,9 @@ -import { render, screen } from "@testing-library/react"; +import { + render, + screen, + waitForElementToBeRemoved, +} from "@testing-library/react"; import userEvent from "@testing-library/user-event"; -import { act } from "react-dom/test-utils"; import { MemoryRouter, Route, Switch } from "react-router"; import { MfaComplete } from "../MfaComplete/MfaComplete"; @@ -53,9 +56,10 @@ describe("Verify SMS MFA", () => { screen.getByLabelText("One-time security code", { exact: false }), "123456" ); - await act(async () => { - await userEvent.click(screen.getByText("Submit")); - }); + userEvent.click(screen.getByText("Submit")); + await waitForElementToBeRemoved(() => + screen.queryByText("Verifying security code …") + ); expect( screen.queryByText("Enter your security code") ).not.toBeInTheDocument(); @@ -74,9 +78,10 @@ describe("Verify SMS MFA", () => { screen.getByLabelText("One-time security code", { exact: false }), "999999" ); - await act(async () => { - await userEvent.click(screen.getByText("Submit")); - }); + userEvent.click(screen.getByText("Submit")); + await waitForElementToBeRemoved(() => + screen.queryByText("Verifying security code …") + ); expect(screen.getByText("incorrect code")).toBeInTheDocument(); expect( screen.queryByText( diff --git a/frontend/src/app/accountCreation/PasswordCreate/PasswordCreate.test.tsx b/frontend/src/app/accountCreation/PasswordCreate/PasswordCreate.test.tsx index 16fb510d36..e923ce0d9b 100644 --- a/frontend/src/app/accountCreation/PasswordCreate/PasswordCreate.test.tsx +++ b/frontend/src/app/accountCreation/PasswordCreate/PasswordCreate.test.tsx @@ -1,6 +1,9 @@ -import { render, screen } from "@testing-library/react"; +import { + render, + screen, + waitForElementToBeRemoved, +} from "@testing-library/react"; import userEvent from "@testing-library/user-event"; -import { act } from "react-dom/test-utils"; import { Provider } from "react-redux"; import { MemoryRouter, Route } from "react-router"; import createMockStore from "redux-mock-store"; @@ -122,9 +125,10 @@ describe("PasswordCreate", () => { "validPASS123!" ); expect(screen.getByText(strengthLabel("Strong"))).toBeInTheDocument(); - await act(async () => { - await userEvent.click(screen.getByText("Continue")); - }); + userEvent.click(screen.getByText("Continue")); + await waitForElementToBeRemoved(() => + screen.queryByText("Validating password …") + ); expect(screen.getByText("Password set successfully.")).toBeInTheDocument(); }); @@ -135,9 +139,10 @@ describe("PasswordCreate", () => { "INvalidPASS123!" ); expect(screen.getByText(strengthLabel("Strong"))).toBeInTheDocument(); - await act(async () => { - await userEvent.click(screen.getByText("Continue")); - }); + userEvent.click(screen.getByText("Continue")); + await waitForElementToBeRemoved(() => + screen.queryByText("Validating password …") + ); expect(screen.getByText("utter failure")).toBeInTheDocument(); }); }); diff --git a/frontend/src/app/accountCreation/SecurityQuestion/SecurityQuestion.test.tsx b/frontend/src/app/accountCreation/SecurityQuestion/SecurityQuestion.test.tsx index 25398fc25a..463bb73e3c 100644 --- a/frontend/src/app/accountCreation/SecurityQuestion/SecurityQuestion.test.tsx +++ b/frontend/src/app/accountCreation/SecurityQuestion/SecurityQuestion.test.tsx @@ -1,6 +1,9 @@ -import { render, screen } from "@testing-library/react"; +import { + render, + screen, + waitForElementToBeRemoved, +} from "@testing-library/react"; import userEvent from "@testing-library/user-event"; -import { act } from "react-dom/test-utils"; import { MemoryRouter, Route } from "react-router"; import { SecurityQuestion } from "./SecurityQuestion"; @@ -76,9 +79,10 @@ describe("SecurityQuestion", () => { screen.getByLabelText("Answer", { exact: false }), "Valid answer" ); - await act(async () => { - await userEvent.click(screen.getByText("Continue")); - }); + userEvent.click(screen.getByText("Continue")); + await waitForElementToBeRemoved(() => + screen.queryByText("Validating security question …") + ); expect( screen.getByText("Recovery question set successfully.") ).toBeInTheDocument(); @@ -93,9 +97,10 @@ describe("SecurityQuestion", () => { screen.getByLabelText("Answer", { exact: false }), "Invalid answer" ); - await act(async () => { - await userEvent.click(screen.getByText("Continue")); - }); + userEvent.click(screen.getByText("Continue")); + await waitForElementToBeRemoved(() => + screen.queryByText("Validating security question …") + ); expect(screen.getByText("catastrophic failure")).toBeInTheDocument(); }); }); diff --git a/frontend/src/app/analytics/Analytics.test.tsx b/frontend/src/app/analytics/Analytics.test.tsx index 07981475cb..371a3ad307 100644 --- a/frontend/src/app/analytics/Analytics.test.tsx +++ b/frontend/src/app/analytics/Analytics.test.tsx @@ -1,6 +1,5 @@ import { render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; -import { act } from "react-dom/test-utils"; import { MockedProvider } from "@apollo/client/testing"; import createMockStore from "redux-mock-store"; import { Provider } from "react-redux"; @@ -233,104 +232,88 @@ describe("Analytics", () => { expect(await screen.findByText("1.8%")).toBeInTheDocument(); }); it("allows filtering by Lincoln Middle School", async () => { - await act(async () => { - await screen.findByText("COVID-19 testing data"); - userEvent.selectOptions(screen.getByLabelText("Testing facility"), [ - "Lincoln Middle School", - ]); - }); + await screen.findByText("COVID-19 testing data"); + userEvent.selectOptions(screen.getByLabelText("Testing facility"), [ + "Lincoln Middle School", + ]); expect(await screen.findByText("72341")).toBeInTheDocument(); expect(await screen.findByText("1000")).toBeInTheDocument(); expect(await screen.findByText("71341")).toBeInTheDocument(); expect(await screen.findByText("1.4%")).toBeInTheDocument(); }); it("allows filtering by Rosa Parks High School", async () => { - await act(async () => { - await screen.findByText("COVID-19 testing data"); - userEvent.selectOptions(screen.getByLabelText("Testing facility"), [ - "Rosa Parks High School", - ]); - }); + await screen.findByText("COVID-19 testing data"); + userEvent.selectOptions(screen.getByLabelText("Testing facility"), [ + "Rosa Parks High School", + ]); expect(await screen.findByText("52479")).toBeInTheDocument(); expect(await screen.findByText("1270")).toBeInTheDocument(); expect(await screen.findByText("51209")).toBeInTheDocument(); expect(await screen.findByText("2.4%")).toBeInTheDocument(); }); it("allows filtering by last day", async () => { - await act(async () => { - await screen.findByText("COVID-19 testing data"); - userEvent.selectOptions(screen.getByLabelText("Date range"), [ - "Last day (24 hours)", - ]); - }); + await screen.findByText("COVID-19 testing data"); + userEvent.selectOptions(screen.getByLabelText("Date range"), [ + "Last day (24 hours)", + ]); expect(await screen.findByText("120")).toBeInTheDocument(); expect(await screen.findByText("11")).toBeInTheDocument(); expect(await screen.findByText("109")).toBeInTheDocument(); expect(await screen.findByText("9.2%")).toBeInTheDocument(); }); it("allows filtering by last week", async () => { - await act(async () => { - await screen.findByText("COVID-19 testing data"); - userEvent.selectOptions(screen.getByLabelText("Date range"), [ - "Last week (7 days)", - ]); - }); + await screen.findByText("COVID-19 testing data"); + userEvent.selectOptions(screen.getByLabelText("Date range"), [ + "Last week (7 days)", + ]); expect(await screen.findByText("124820")).toBeInTheDocument(); }); it("allows filtering by last month", async () => { - await act(async () => { - await screen.findByText("COVID-19 testing data"); - userEvent.selectOptions(screen.getByLabelText("Date range"), [ - "Last month (30 days)", - ]); - }); + await screen.findByText("COVID-19 testing data"); + userEvent.selectOptions(screen.getByLabelText("Date range"), [ + "Last month (30 days)", + ]); expect(await screen.findByText("623492")).toBeInTheDocument(); expect(await screen.findByText("34971")).toBeInTheDocument(); expect(await screen.findByText("588521")).toBeInTheDocument(); expect(await screen.findByText("5.6%")).toBeInTheDocument(); }); it("allows filtering by a custom date range", async () => { - await act(async () => { - await screen.findByText("COVID-19 testing data"); - userEvent.selectOptions(screen.getByLabelText("Date range"), [ - "Custom date range", - ]); - await screen.findByText("COVID-19 testing data"); - await userEvent.type( - screen.getAllByTestId("date-picker-external-input")[0], - "07/01/2021" - ); - await screen.findByText("COVID-19 testing data"); - await userEvent.type( - screen.getAllByTestId("date-picker-external-input")[1], - "07/31/2021" - ); - }); + await screen.findByText("COVID-19 testing data"); + userEvent.selectOptions(screen.getByLabelText("Date range"), [ + "Custom date range", + ]); + await screen.findByText("COVID-19 testing data"); + userEvent.type( + screen.getAllByTestId("date-picker-external-input")[0], + "07/01/2021" + ); + await screen.findByText("COVID-19 testing data"); + await userEvent.type( + screen.getAllByTestId("date-picker-external-input")[1], + "07/31/2021" + ); expect(await screen.findByText("14982")).toBeInTheDocument(); expect(await screen.findByText("953")).toBeInTheDocument(); expect(await screen.findByText("14029")).toBeInTheDocument(); expect(await screen.findByText("6.4%")).toBeInTheDocument(); }); it("shows N/A for positivity rate at Empty School", async () => { - await act(async () => { - await screen.findByText("COVID-19 testing data"); - userEvent.selectOptions(screen.getByLabelText("Testing facility"), [ - "Empty School", - ]); - }); + await screen.findByText("COVID-19 testing data"); + userEvent.selectOptions(screen.getByLabelText("Testing facility"), [ + "Empty School", + ]); expect(await screen.findByText("N/A")).toBeInTheDocument(); }); it("shows 0% for positivity rate at Empty School over last month", async () => { - await act(async () => { - await screen.findByText("COVID-19 testing data"); - userEvent.selectOptions(screen.getByLabelText("Testing facility"), [ - "Empty School", - ]); - await screen.findByText("COVID-19 testing data"); - userEvent.selectOptions(screen.getByLabelText("Date range"), [ - "Last month (30 days)", - ]); - }); + await screen.findByText("COVID-19 testing data"); + userEvent.selectOptions(screen.getByLabelText("Testing facility"), [ + "Empty School", + ]); + await screen.findByText("COVID-19 testing data"); + userEvent.selectOptions(screen.getByLabelText("Date range"), [ + "Last month (30 days)", + ]); expect(await screen.findByText("0.0%")).toBeInTheDocument(); }); }); diff --git a/frontend/src/app/commonComponents/MultiSelect/MultiSelectDropdown/MultiSelectDropdown.test.tsx b/frontend/src/app/commonComponents/MultiSelect/MultiSelectDropdown/MultiSelectDropdown.test.tsx index 78579114f2..2fb8a1f540 100644 --- a/frontend/src/app/commonComponents/MultiSelect/MultiSelectDropdown/MultiSelectDropdown.test.tsx +++ b/frontend/src/app/commonComponents/MultiSelect/MultiSelectDropdown/MultiSelectDropdown.test.tsx @@ -1,5 +1,4 @@ -import React from "react"; -import { render, fireEvent } from "@testing-library/react"; +import { render, fireEvent, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { @@ -24,7 +23,7 @@ const fruitOptions: MultiSelectDropdownOption[] = [ describe("MultiSelectDropdown component", () => { it("renders without errors", () => { - const { getByTestId } = render( + render( { onChange={jest.fn()} /> ); - expect(getByTestId("multi-select")).toBeInTheDocument(); + expect(screen.getByTestId("multi-select")).toBeInTheDocument(); }); it("renders input element", () => { - const { getByRole } = render( + render( { onChange={jest.fn()} /> ); - expect(getByRole("multi-select-input")).toBeInTheDocument(); - expect(getByRole("multi-select-input")).toBeInstanceOf(HTMLInputElement); + expect(screen.getByRole("multi-select-input")).toBeInTheDocument(); + expect(screen.getByRole("multi-select-input")).toBeInstanceOf( + HTMLInputElement + ); }); it("renders hidden options list on load", () => { - const { getByTestId } = render( + render( { onChange={jest.fn()} /> ); - expect(getByTestId("multi-select-option-list")).toBeInstanceOf( + expect(screen.getByTestId("multi-select-option-list")).toBeInstanceOf( HTMLUListElement ); - expect(getByTestId("multi-select-input")).toHaveAttribute( + expect(screen.getByTestId("multi-select-input")).toHaveAttribute( "aria-expanded", "false" ); - expect(getByTestId("multi-select-option-list")).not.toBeVisible(); + expect(screen.getByTestId("multi-select-option-list")).not.toBeVisible(); }); it("shows options list when input toggle clicked", () => { - const { getByTestId } = render( + render( { /> ); - userEvent.click(getByTestId("multi-select-toggle")); + userEvent.click(screen.getByTestId("multi-select-toggle")); - expect(getByTestId("multi-select-option-list")).toBeVisible(); + expect(screen.getByTestId("multi-select-option-list")).toBeVisible(); }); it("shows list when input is clicked", () => { - const { getByTestId } = render( + render( { /> ); - userEvent.click(getByTestId("multi-select-input")); + userEvent.click(screen.getByTestId("multi-select-input")); - expect(getByTestId("multi-select-option-list")).toBeVisible(); + expect(screen.getByTestId("multi-select-option-list")).toBeVisible(); }); it("shows list when input is typed into", () => { - const { getByTestId } = render( + render( { /> ); - userEvent.type(getByTestId("multi-select-input"), "b"); + userEvent.type(screen.getByTestId("multi-select-input"), "b"); - expect(getByTestId("multi-select-option-list")).toBeVisible(); + expect(screen.getByTestId("multi-select-option-list")).toBeVisible(); }); it("can be disabled", () => { - const { getByTestId } = render( + render( { disabled={true} /> ); - expect(getByTestId("multi-select-input")).toBeDisabled(); + expect(screen.getByTestId("multi-select-input")).toBeDisabled(); }); it("does not show the list when clicking the disabled component", () => { - const { getByTestId } = render( + render( { disabled={true} /> ); - userEvent.click(getByTestId("multi-select-toggle")); + userEvent.click(screen.getByTestId("multi-select-toggle")); - expect(getByTestId("multi-select-option-list")).not.toBeVisible(); + expect(screen.getByTestId("multi-select-option-list")).not.toBeVisible(); }); it("renders input with custom props if passed in", () => { - const { getByTestId } = render( + render( { /> ); - expect(getByTestId("multi-select-input")).toHaveAttribute("required"); - expect(getByTestId("multi-select-input")).toHaveAttribute( + expect(screen.getByTestId("multi-select-input")).toBeRequired(); + expect(screen.getByTestId("multi-select-input")).toHaveAttribute( "role", "testing" ); @@ -160,7 +161,7 @@ describe("MultiSelectDropdown component", () => { describe("filtering", () => { it("shows all options on initial load when no default value exists", () => { - const { getByTestId } = render( + render( { /> ); - userEvent.click(getByTestId("multi-select-input")); + userEvent.click(screen.getByTestId("multi-select-input")); - expect(getByTestId("multi-select-option-list").children.length).toBe( - fruitOptions.length - ); + expect( + screen.getByTestId("multi-select-option-list").children.length + ).toBe(fruitOptions.length); }); it("shows all options on initial load when a default value exists", () => { - const { getByTestId } = render( + render( { /> ); - userEvent.click(getByTestId("multi-select-input")); + userEvent.click(screen.getByTestId("multi-select-input")); - expect(getByTestId("multi-select-option-list").children.length).toBe( - fruitOptions.length - ); + expect( + screen.getByTestId("multi-select-option-list").children.length + ).toBe(fruitOptions.length); }); it("filters the options list after a character is typed", () => { - const { getByTestId } = render( + render( { /> ); - const input = getByTestId("multi-select-input"); + const input = screen.getByTestId("multi-select-input"); userEvent.type(input, "a"); - expect(getByTestId("multi-select-option-list").children.length).toEqual( - 5 - ); + expect( + screen.getByTestId("multi-select-option-list").children.length + ).toEqual(5); }); it("persists filter options if dropdown is closed and open without selection", () => { - const { getByTestId } = render( + render( { /> ); - const input = getByTestId("multi-select-input"); + const input = screen.getByTestId("multi-select-input"); userEvent.type(input, "yu"); - userEvent.click(getByTestId("multi-select-toggle")); + userEvent.click(screen.getByTestId("multi-select-toggle")); - expect(getByTestId("multi-select-option-list").children.length).toEqual( - 6 - ); + expect( + screen.getByTestId("multi-select-option-list").children.length + ).toEqual(6); - userEvent.click(getByTestId("multi-select-toggle")); - expect(getByTestId("multi-select-option-list").children.length).toEqual( - 6 - ); + userEvent.click(screen.getByTestId("multi-select-toggle")); + expect( + screen.getByTestId("multi-select-option-list").children.length + ).toEqual(6); }); it("clears filter when item selected", () => { - const { getByTestId } = render( + render( { /> ); - const input = getByTestId("multi-select-input"); + const input = screen.getByTestId("multi-select-input"); userEvent.type(input, "ap"); - userEvent.click(getByTestId("multi-select-option-Apples")); + userEvent.click(screen.getByTestId("multi-select-option-Apples")); - expect(getByTestId("multi-select-option-list").children.length).toEqual( - fruitOptions.length - ); + expect( + screen.getByTestId("multi-select-option-list").children.length + ).toEqual(fruitOptions.length); }); it("shows no results message when there is no match", () => { - const { getByTestId } = render( + render( { /> ); - userEvent.type(getByTestId("multi-select-input"), "zz"); + userEvent.type(screen.getByTestId("multi-select-input"), "zz"); - const firstItem = getByTestId("multi-select-option-list").children[0]; + const firstItem = screen.getByTestId("multi-select-option-list") + .children[0]; expect(firstItem).not.toHaveFocus(); expect(firstItem).not.toHaveAttribute("tabindex", "0"); expect(firstItem).toHaveTextContent("No results found"); }); it("shows all results when typed value is cleared", () => { - const { getByTestId } = render( + render( { /> ); - const input = getByTestId("multi-select-input"); + const input = screen.getByTestId("multi-select-input"); userEvent.type(input, "apple"); userEvent.clear(input); - expect(getByTestId("multi-select-option-list").children.length).toEqual( - fruitOptions.length - ); + expect( + screen.getByTestId("multi-select-option-list").children.length + ).toEqual(fruitOptions.length); }); }); describe("keyboard actions", () => { it("clears input when there is no match and enter is pressed", () => { - const { getByTestId } = render( + render( { /> ); - userEvent.type(getByTestId("multi-select-input"), "zzz{enter}"); + userEvent.type(screen.getByTestId("multi-select-input"), "zzz{enter}"); - expect(getByTestId("multi-select-option-list")).not.toBeVisible(); - expect(getByTestId("multi-select-input")).toHaveValue(""); - expect(getByTestId("multi-select-input")).toHaveFocus(); + expect(screen.getByTestId("multi-select-option-list")).not.toBeVisible(); + expect(screen.getByTestId("multi-select-input")).toHaveValue(""); + expect(screen.getByTestId("multi-select-input")).toHaveFocus(); }); it("clears filter when there is no match and enter is pressed", () => { - const { getByTestId } = render( + render( { /> ); - userEvent.type(getByTestId("multi-select-input"), "zzz{enter}"); + userEvent.type(screen.getByTestId("multi-select-input"), "zzz{enter}"); - expect(getByTestId("multi-select-option-list")).not.toBeVisible(); - expect(getByTestId("multi-select-option-list").children.length).toBe( - fruitOptions.length - ); + expect(screen.getByTestId("multi-select-option-list")).not.toBeVisible(); + expect( + screen.getByTestId("multi-select-option-list").children.length + ).toBe(fruitOptions.length); }); it("focuses the first filtered option with tab", () => { - const { getByTestId } = render( + render( { /> ); - userEvent.type(getByTestId("multi-select-input"), "a"); + userEvent.type(screen.getByTestId("multi-select-input"), "a"); userEvent.tab(); - const firstItem = getByTestId("multi-select-option-list").children[0]; + const firstItem = screen.getByTestId("multi-select-option-list") + .children[0]; expect(firstItem).toHaveFocus(); expect(firstItem).toHaveAttribute("tabindex", "0"); }); it("focuses the first option with tab", () => { - const { getByTestId } = render( + render( { /> ); - userEvent.click(getByTestId("multi-select-input")); // open menu + userEvent.click(screen.getByTestId("multi-select-input")); // open menu userEvent.tab(); - expect(getByTestId("multi-select-option-Apples")).toHaveFocus(); - expect(getByTestId("multi-select-option-Apples")).toHaveAttribute( + expect(screen.getByTestId("multi-select-option-Apples")).toHaveFocus(); + expect(screen.getByTestId("multi-select-option-Apples")).toHaveAttribute( "tabindex", "0" ); @@ -367,7 +370,7 @@ describe("MultiSelectDropdown component", () => { it("selects the focused option with tab", () => { const onChange = jest.fn(); - const { getByTestId } = render( + render( { /> ); // focus oranges - userEvent.type(getByTestId("multi-select-input"), "oran"); + userEvent.type(screen.getByTestId("multi-select-input"), "oran"); userEvent.tab(); // select oranges @@ -389,7 +392,7 @@ describe("MultiSelectDropdown component", () => { }); it("switches focus when there are no filtered options", () => { - const { getByTestId } = render( + render( { /> ); - const comboBoxInput = getByTestId("multi-select-input"); + const comboBoxInput = screen.getByTestId("multi-select-input"); userEvent.type(comboBoxInput, "zzz"); userEvent.tab(); @@ -407,7 +410,7 @@ describe("MultiSelectDropdown component", () => { it("selects the focused option with enter", () => { const onChange = jest.fn(); - const { getByTestId } = render( + render( { /> ); - userEvent.type(getByTestId("multi-select-input"), "Ora"); + userEvent.type(screen.getByTestId("multi-select-input"), "Ora"); userEvent.tab(); - userEvent.type(getByTestId("multi-select-option-Oranges"), "{enter}"); + userEvent.type( + screen.getByTestId("multi-select-option-Oranges"), + "{enter}" + ); expect(onChange).toHaveBeenLastCalledWith({ label: "Oranges", @@ -427,7 +433,7 @@ describe("MultiSelectDropdown component", () => { }); it("focuses the next option when down arrow is pressed", () => { - const { getByTestId } = render( + render( { /> ); - userEvent.type(getByTestId("multi-select-input"), "a"); + userEvent.type(screen.getByTestId("multi-select-input"), "a"); userEvent.tab(); - fireEvent.keyDown(getByTestId("multi-select-option-Apples"), { + fireEvent.keyDown(screen.getByTestId("multi-select-option-Apples"), { key: "ArrowDown", }); - expect(getByTestId("multi-select-option-Bananas")).toHaveFocus(); + expect(screen.getByTestId("multi-select-option-Bananas")).toHaveFocus(); }); it("focuses the previous option when up arrow is pressed", () => { - const { getByTestId } = render( + render( { /> ); - userEvent.type(getByTestId("multi-select-input"), "a"); + userEvent.type(screen.getByTestId("multi-select-input"), "a"); userEvent.tab(); - fireEvent.keyDown(getByTestId("multi-select-option-Apples"), { + fireEvent.keyDown(screen.getByTestId("multi-select-option-Apples"), { key: "ArrowDown", }); - fireEvent.keyDown(getByTestId("multi-select-option-Bananas"), { + fireEvent.keyDown(screen.getByTestId("multi-select-option-Bananas"), { key: "ArrowDown", }); - fireEvent.keyDown(getByTestId("multi-select-option-Grapes"), { + fireEvent.keyDown(screen.getByTestId("multi-select-option-Grapes"), { key: "ArrowUp", }); - expect(getByTestId("multi-select-option-Bananas")).toHaveFocus(); + expect(screen.getByTestId("multi-select-option-Bananas")).toHaveFocus(); }); it("opens the menu when down arrow is pressed in the input", () => { - const { getByTestId } = render( + render( { /> ); - userEvent.click(getByTestId("multi-select-input")); - fireEvent.keyDown(getByTestId("multi-select-input"), { + userEvent.click(screen.getByTestId("multi-select-input")); + fireEvent.keyDown(screen.getByTestId("multi-select-input"), { key: "ArrowDown", }); - expect(getByTestId("multi-select-option-list")).toBeVisible(); - expect(getByTestId("multi-select-option-Apples")).toHaveFocus(); + expect(screen.getByTestId("multi-select-option-list")).toBeVisible(); + expect(screen.getByTestId("multi-select-option-Apples")).toHaveFocus(); }); it("does not change focus when last option is focused and down arrow is pressed", () => { - const { getByTestId } = render( + render( { /> ); - fireEvent.click(getByTestId("multi-select-input")); - userEvent.hover(getByTestId("multi-select-option-Strawberries")); - fireEvent.keyDown(getByTestId("multi-select-option-Strawberries"), { - key: "ArrowDown", - }); + fireEvent.click(screen.getByTestId("multi-select-input")); + userEvent.hover(screen.getByTestId("multi-select-option-Strawberries")); + fireEvent.keyDown( + screen.getByTestId("multi-select-option-Strawberries"), + { + key: "ArrowDown", + } + ); - expect(getByTestId("multi-select-option-Strawberries")).toHaveFocus(); + expect( + screen.getByTestId("multi-select-option-Strawberries") + ).toHaveFocus(); }); it("does not close menu when an option is selected and the first option is focused and up arrow is pressed", () => { - const { getByTestId } = render( + render( { ); // Apple is the item at top of list - userEvent.hover(getByTestId("multi-select-option-Apples")); - fireEvent.keyDown(getByTestId("multi-select-option-Apples"), { + userEvent.hover(screen.getByTestId("multi-select-option-Apples")); + fireEvent.keyDown(screen.getByTestId("multi-select-option-Apples"), { key: "ArrowUp", }); - expect(getByTestId("multi-select-option-Apples")).toHaveFocus(); - expect(getByTestId("multi-select-input")).toHaveAttribute( + expect(screen.getByTestId("multi-select-option-Apples")).toHaveFocus(); + expect(screen.getByTestId("multi-select-input")).toHaveAttribute( "aria-expanded", "true" ); - expect(getByTestId("multi-select-option-list")).toBeVisible(); + expect(screen.getByTestId("multi-select-option-list")).toBeVisible(); }); it("clears out the input when options list is closed and no matching options is selected", () => { - const { getByTestId } = render( + render( { /> ); - const comboBoxInput = getByTestId("multi-select-input"); + const comboBoxInput = screen.getByTestId("multi-select-input"); userEvent.type(comboBoxInput, "a{enter}"); expect(comboBoxInput).toHaveValue(""); }); @@ -550,7 +561,7 @@ describe("MultiSelectDropdown component", () => { describe("mouse actions", () => { it("displays options list when input is clicked", () => { - const { getByTestId } = render( + render( { /> ); - fireEvent.click(getByTestId("multi-select-input")); + fireEvent.click(screen.getByTestId("multi-select-input")); - expect(getByTestId("multi-select-input")).toHaveAttribute( + expect(screen.getByTestId("multi-select-input")).toHaveAttribute( "aria-expanded", "true" ); - expect(getByTestId("multi-select-option-list")).toBeVisible(); - expect(getByTestId("multi-select-option-list").childElementCount).toEqual( - fruitOptions.length - ); + expect(screen.getByTestId("multi-select-option-list")).toBeVisible(); + expect( + screen.getByTestId("multi-select-option-list").childElementCount + ).toEqual(fruitOptions.length); }); it("displays options list when input is clicked twice", () => { - const { getByTestId } = render( + render( { /> ); - userEvent.dblClick(getByTestId("multi-select-input")); + userEvent.dblClick(screen.getByTestId("multi-select-input")); - expect(getByTestId("multi-select-input")).toHaveAttribute( + expect(screen.getByTestId("multi-select-input")).toHaveAttribute( "aria-expanded", "true" ); - expect(getByTestId("multi-select-option-list")).toBeVisible(); + expect(screen.getByTestId("multi-select-option-list")).toBeVisible(); }); it("hides options list when clicking away and input has focus", () => { - const { getByTestId } = render( + render( { /> ); - fireEvent.click(getByTestId("multi-select-input")); - fireEvent.blur(getByTestId("multi-select-input")); + fireEvent.click(screen.getByTestId("multi-select-input")); + fireEvent.blur(screen.getByTestId("multi-select-input")); - expect(getByTestId("multi-select-input")).toHaveAttribute( + expect(screen.getByTestId("multi-select-input")).toHaveAttribute( "aria-expanded", "false" ); - expect(getByTestId("multi-select-option-list")).not.toBeVisible(); + expect(screen.getByTestId("multi-select-option-list")).not.toBeVisible(); }); it("hides options list when clicking away and a specific option has focus", () => { - const { getByTestId } = render( + render( { /> ); - fireEvent.click(getByTestId("multi-select-input")); - userEvent.hover(getByTestId("multi-select-option-Blueberries")); + fireEvent.click(screen.getByTestId("multi-select-input")); + userEvent.hover(screen.getByTestId("multi-select-option-Blueberries")); - fireEvent.blur(getByTestId("multi-select-option-Blueberries")); + fireEvent.blur(screen.getByTestId("multi-select-option-Blueberries")); - expect(getByTestId("multi-select-input")).toHaveAttribute( + expect(screen.getByTestId("multi-select-input")).toHaveAttribute( "aria-expanded", "false" ); - expect(getByTestId("multi-select-option-list")).not.toBeVisible(); + expect(screen.getByTestId("multi-select-option-list")).not.toBeVisible(); }); it("shows and hides options list when toggle is clicked", () => { - const { getByTestId } = render( + render( { /> ); - fireEvent.click(getByTestId("multi-select-toggle")); + fireEvent.click(screen.getByTestId("multi-select-toggle")); - expect(getByTestId("multi-select-input")).toHaveAttribute( + expect(screen.getByTestId("multi-select-input")).toHaveAttribute( "aria-expanded", "true" ); - expect(getByTestId("multi-select-option-list")).toBeVisible(); + expect(screen.getByTestId("multi-select-option-list")).toBeVisible(); - fireEvent.click(getByTestId("multi-select-toggle")); + fireEvent.click(screen.getByTestId("multi-select-toggle")); - expect(getByTestId("multi-select-input")).toHaveAttribute( + expect(screen.getByTestId("multi-select-input")).toHaveAttribute( "aria-expanded", "false" ); - expect(getByTestId("multi-select-option-list")).not.toBeVisible(); + expect(screen.getByTestId("multi-select-option-list")).not.toBeVisible(); }); it("selects an item by clicking on an option", () => { const onChange = jest.fn(); - const { getByTestId } = render( + render( { /> ); - fireEvent.click(getByTestId("multi-select-toggle")); - fireEvent.click(getByTestId("multi-select-option-Apples")); + fireEvent.click(screen.getByTestId("multi-select-toggle")); + fireEvent.click(screen.getByTestId("multi-select-option-Apples")); expect(onChange).toHaveBeenLastCalledWith({ label: "Apples", @@ -681,7 +692,7 @@ describe("MultiSelectDropdown component", () => { it("persists input text when items list is blurred", () => { const onChange = jest.fn(); - const { getByTestId } = render( + render( <>
{ ); - userEvent.click(getByTestId("multi-select-toggle")); - userEvent.click(getByTestId("multi-select-option-Apples")); - fireEvent.blur(getByTestId("multi-select-input")); + userEvent.click(screen.getByTestId("multi-select-toggle")); + userEvent.click(screen.getByTestId("multi-select-option-Apples")); + fireEvent.blur(screen.getByTestId("multi-select-input")); expect(onChange).toHaveBeenLastCalledWith({ label: "Apples", @@ -704,7 +715,7 @@ describe("MultiSelectDropdown component", () => { }); it("persists input text if dropdown is closed and open without selection", () => { - const { getByTestId } = render( + render( { /> ); - const input = getByTestId("multi-select-input"); + const input = screen.getByTestId("multi-select-input"); userEvent.type(input, "gr"); - userEvent.click(getByTestId("multi-select-toggle")); + userEvent.click(screen.getByTestId("multi-select-toggle")); expect(input).toHaveValue("gr"); - userEvent.click(getByTestId("multi-select-toggle")); + userEvent.click(screen.getByTestId("multi-select-toggle")); expect(input).toHaveValue("gr"); }); it("clears input with item selected on click", () => { const onChange = jest.fn(); - const { getByTestId } = render( + render( { /> ); - const input = getByTestId("multi-select-input"); + const input = screen.getByTestId("multi-select-input"); userEvent.type(input, "Gr"); - fireEvent.click(getByTestId("multi-select-option-Grapes")); + fireEvent.click(screen.getByTestId("multi-select-option-Grapes")); expect(onChange).toHaveBeenLastCalledWith({ label: "Grapes", @@ -745,7 +756,7 @@ describe("MultiSelectDropdown component", () => { }); it("focuses an option on hover", () => { - const { getByTestId } = render( + render( { /> ); - userEvent.click(getByTestId("multi-select-toggle")); - userEvent.hover(getByTestId("multi-select-option-Blueberries")); + userEvent.click(screen.getByTestId("multi-select-toggle")); + userEvent.hover(screen.getByTestId("multi-select-option-Blueberries")); - expect(getByTestId("multi-select-option-Blueberries")).toHaveClass( + expect(screen.getByTestId("multi-select-option-Blueberries")).toHaveClass( "usa-combo-box__list-option--focused" ); - userEvent.hover(getByTestId("multi-select-option-Grapes")); - expect(getByTestId("multi-select-option-Blueberries")).not.toHaveClass( - "usa-combo-box__list-option--focused" - ); - expect(getByTestId("multi-select-option-Grapes")).toHaveClass( + userEvent.hover(screen.getByTestId("multi-select-option-Grapes")); + expect( + screen.getByTestId("multi-select-option-Blueberries") + ).not.toHaveClass("usa-combo-box__list-option--focused"); + expect(screen.getByTestId("multi-select-option-Grapes")).toHaveClass( "usa-combo-box__list-option--focused" ); }); it("clears focus when clicking outside of the component", () => { - const { getByTestId } = render( + render( <>
{ ); - userEvent.click(getByTestId("multi-select-toggle")); - userEvent.click(getByTestId("outside")); - expect(getByTestId("multi-select-input")).not.toHaveFocus(); + userEvent.click(screen.getByTestId("multi-select-toggle")); + userEvent.click(screen.getByTestId("outside")); + expect(screen.getByTestId("multi-select-input")).not.toHaveFocus(); }); }); describe("accessibility and internationalization", () => { it("adds correct aria attributes on options when an item is selected", () => { - const { getByTestId } = render( + render( { onChange={jest.fn()} /> ); - const list = getByTestId("multi-select-option-list"); + const list = screen.getByTestId("multi-select-option-list"); // open options list - fireEvent.click(getByTestId("multi-select-input")); + fireEvent.click(screen.getByTestId("multi-select-input")); userEvent.tab(); Object.values(list.children).forEach((node) => { - if (node === getByTestId("multi-select-option-Apples")) { + if (node === screen.getByTestId("multi-select-option-Apples")) { expect(node).toHaveAttribute("tabindex", "0"); expect(node).toHaveAttribute("aria-selected", "true"); } else { @@ -818,7 +829,7 @@ describe("MultiSelectDropdown component", () => { }); it("allows no results message to be customized", () => { - const { getByTestId } = render( + render( { noResults="NOTHING" /> ); - userEvent.type(getByTestId("multi-select-input"), "zzz"); - const firstItem = getByTestId("multi-select-option-list").children[0]; + userEvent.type(screen.getByTestId("multi-select-input"), "zzz"); + const firstItem = screen.getByTestId("multi-select-option-list") + .children[0]; expect(firstItem).toHaveTextContent("NOTHING"); }); }); diff --git a/frontend/src/app/commonComponents/NewFeatureTag.test.tsx b/frontend/src/app/commonComponents/NewFeatureTag.test.tsx index 2f748237df..bb92b86cab 100644 --- a/frontend/src/app/commonComponents/NewFeatureTag.test.tsx +++ b/frontend/src/app/commonComponents/NewFeatureTag.test.tsx @@ -23,7 +23,7 @@ describe("NewFeatureTag", () => { render(); }); it("renders the new tag", () => { - expect(screen.queryByText("New", { exact: false })).toBeInTheDocument(); + expect(screen.getByText("New", { exact: false })).toBeInTheDocument(); }); }); }); diff --git a/frontend/src/app/commonComponents/Page/Page.test.tsx b/frontend/src/app/commonComponents/Page/Page.test.tsx index b8b5aa9587..0fa5cca296 100644 --- a/frontend/src/app/commonComponents/Page/Page.test.tsx +++ b/frontend/src/app/commonComponents/Page/Page.test.tsx @@ -1,4 +1,4 @@ -import { render } from "@testing-library/react"; +import { render, screen } from "@testing-library/react"; import Page from "./Page"; @@ -10,8 +10,8 @@ describe("Page", () => { }); describe("With children", () => { it("displays children", () => { - const { getByText } = render(Hello World); - expect(getByText("Hello World")).toBeInTheDocument(); + render(Hello World); + expect(screen.getByText("Hello World")).toBeInTheDocument(); }); }); }); diff --git a/frontend/src/app/commonComponents/Pagination.test.tsx b/frontend/src/app/commonComponents/Pagination.test.tsx index 89dac65f42..4e6f7f4dff 100644 --- a/frontend/src/app/commonComponents/Pagination.test.tsx +++ b/frontend/src/app/commonComponents/Pagination.test.tsx @@ -35,7 +35,7 @@ const testCases = { describe("Pagination", () => { it("should render Pagination cases", () => { - Object.entries(testCases).forEach(([name, tc], index) => { + Object.entries(testCases).forEach(([name, tc], _index) => { const props = { ...defaults, ...tc } as any; const { container } = render( diff --git a/frontend/src/app/commonComponents/__test__/ErrorPage.test.tsx b/frontend/src/app/commonComponents/__test__/ErrorPage.test.tsx index 2abf7c7fe0..b3c0fb9985 100644 --- a/frontend/src/app/commonComponents/__test__/ErrorPage.test.tsx +++ b/frontend/src/app/commonComponents/__test__/ErrorPage.test.tsx @@ -1,23 +1,22 @@ -import { render } from "@testing-library/react"; +import { render, screen } from "@testing-library/react"; import { MemoryRouter } from "react-router-dom"; import ErrorPage from "../ErrorPage"; describe("ErrorPage", () => { it("displays the correct error message", () => { - const { container, getByText } = render( + render( ); - expect(getByText("Something went wrong :(")).toBeInTheDocument(); + expect(screen.getByText("Something went wrong :(")).toBeInTheDocument(); expect( - getByText("Please try refreshing your browser.") + screen.getByText("Please try refreshing your browser.") ).toBeInTheDocument(); - expect(getByText("support@simplereport.gov")).toHaveAttribute( + expect(screen.getByText("support@simplereport.gov")).toHaveAttribute( "href", "mailto:support@simplereport.gov" ); - expect(container).toMatchSnapshot(); }); }); diff --git a/frontend/src/app/commonComponents/__test__/Header.test.tsx b/frontend/src/app/commonComponents/__test__/Header.test.tsx index 87464bbdf0..1ef1ee7b00 100644 --- a/frontend/src/app/commonComponents/__test__/Header.test.tsx +++ b/frontend/src/app/commonComponents/__test__/Header.test.tsx @@ -1,4 +1,4 @@ -import { render, screen, waitFor } from "@testing-library/react"; +import { render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { Provider } from "react-redux"; import { MemoryRouter } from "react-router"; @@ -58,14 +58,10 @@ describe("Header.tsx", () => { it("displays the support link correctly", async () => { process.env.REACT_APP_IS_TRAINING_SITE = "false"; render(); - await waitFor(() => { - userEvent.click(screen.getByTestId("user-button")); - }); + userEvent.click(screen.getByTestId("user-button")); expect(screen.getByTestId("support-link")).toBeVisible(); - await waitFor(() => { - userEvent.click(screen.getByTestId("support-link")); - expect(trackEventMock).toHaveBeenCalledWith({ name: "Support" }); - }); + userEvent.click(screen.getByTestId("support-link")); + expect(trackEventMock).toHaveBeenCalledWith({ name: "Support" }); }); it("it does not render login links", () => { expect( @@ -80,9 +76,7 @@ describe("Header.tsx", () => { ); const dropdown = await screen.findAllByRole("option"); - await waitFor(() => { - userEvent.selectOptions(dropdown[1].closest("select")!, "2"); - }); + userEvent.selectOptions(dropdown[1].closest("select")!, "2"); expect( await screen.findByText("Facility 2 is selected") ).toBeInTheDocument(); diff --git a/frontend/src/app/commonComponents/__test__/LinkWithQuery.test.tsx b/frontend/src/app/commonComponents/__test__/LinkWithQuery.test.tsx index f6f0d0f959..469d50b638 100644 --- a/frontend/src/app/commonComponents/__test__/LinkWithQuery.test.tsx +++ b/frontend/src/app/commonComponents/__test__/LinkWithQuery.test.tsx @@ -1,25 +1,25 @@ -import { render } from "@testing-library/react"; +import { render, screen } from "@testing-library/react"; import { MemoryRouter } from "react-router"; import { LinkWithQuery } from "../LinkWithQuery"; describe("LinkWithQuery", () => { it("adds query params to a link", async () => { - const { findByRole } = render( + render( Go to route ); - const link = await findByRole("link"); + const link = await screen.findByRole("link"); expect(link.getAttribute("href")?.split("?")[1]).toBe("foo=bar"); }); it("leaves links alone if there are no query params", async () => { - const { findByRole } = render( + render( Go to route ); - const link = await findByRole("link"); - expect(link.getAttribute("href")).toBe("/some/route"); + const link = await screen.findByRole("link"); + expect(link).toHaveAttribute("href", "/some/route"); }); }); diff --git a/frontend/src/app/commonComponents/__test__/__snapshots__/ErrorPage.test.tsx.snap b/frontend/src/app/commonComponents/__test__/__snapshots__/ErrorPage.test.tsx.snap deleted file mode 100644 index 9bfb5c17ac..0000000000 --- a/frontend/src/app/commonComponents/__test__/__snapshots__/ErrorPage.test.tsx.snap +++ /dev/null @@ -1,103 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`ErrorPage displays the correct error message 1`] = ` -
-
-
-
-
-
- U.S. flag -
-
-

- An official website of the United States government -

- -
- -
-
-
-
-
-
- - SimpleReport - -
-
-
-
-

- Something went wrong :( -

-

- Please try refreshing your browser. -

-

- If the problem continues, contact - - - support@simplereport.gov - - - for support. -

-
-
-
-`; diff --git a/frontend/src/app/constants/index.tsx b/frontend/src/app/constants/index.tsx index 8e5e8410c2..5da6b1221b 100644 --- a/frontend/src/app/constants/index.tsx +++ b/frontend/src/app/constants/index.tsx @@ -1,3 +1,4 @@ +/* eslint-disable unused-imports/no-unused-vars */ import { TFunction } from "i18next"; import { useTranslation } from "react-i18next"; diff --git a/frontend/src/app/facilitySelect/FacilitySelect.test.tsx b/frontend/src/app/facilitySelect/FacilitySelect.test.tsx index 87be19b6b0..4ed6b04e7c 100644 --- a/frontend/src/app/facilitySelect/FacilitySelect.test.tsx +++ b/frontend/src/app/facilitySelect/FacilitySelect.test.tsx @@ -1,14 +1,12 @@ -import React from "react"; import configureStore from "redux-mock-store"; -import renderer from "react-test-renderer"; import { Provider } from "react-redux"; +import { render, screen } from "@testing-library/react"; import FacilitySelect from "./FacilitySelect"; const mockStore = configureStore([]); describe("FacilitySelect", () => { - let component: any; const mockSetActiveFacility = jest.fn(); beforeEach(() => { @@ -26,7 +24,7 @@ describe("FacilitySelect", () => { ], }); - component = renderer.create( + render( { ); }); - it("should render with a value", () => { - expect(component.toJSON()).toMatchSnapshot(); - }); - describe("On facility select", () => { - beforeEach(() => { - renderer.act(() => { - component.root.findAllByType("button")[0].props.onClick(); - }); + beforeEach(async () => { + (await screen.findAllByRole("button"))[0].click(); }); it("should call setActiveFacility once", () => { expect(mockSetActiveFacility).toHaveBeenCalledTimes(1); diff --git a/frontend/src/app/facilitySelect/WithFacility.test.tsx b/frontend/src/app/facilitySelect/WithFacility.test.tsx index 3957ed2771..4c46d1fa3d 100644 --- a/frontend/src/app/facilitySelect/WithFacility.test.tsx +++ b/frontend/src/app/facilitySelect/WithFacility.test.tsx @@ -1,7 +1,6 @@ import { Provider } from "react-redux"; -import renderer from "react-test-renderer"; import configureStore from "redux-mock-store"; -import { act, render, screen, waitFor } from "@testing-library/react"; +import { render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { MockedProvider } from "@apollo/client/testing"; import { MemoryRouter as Router } from "react-router"; @@ -53,7 +52,6 @@ const mocks = [ describe("WithFacility", () => { let store: any; - let component: any; describe("With zero facilities", () => { beforeEach(() => { @@ -70,7 +68,7 @@ describe("WithFacility", () => { facilities: [], }); store.dispatch = jest.fn(); - component = renderer.create( + render( App @@ -80,7 +78,9 @@ describe("WithFacility", () => { }); it("should notify user to contact an admin", () => { - expect(component.toJSON()).toMatchSnapshot(); + expect( + screen.getByText("Ask an administrator", { exact: false }) + ).toBeInTheDocument(); }); }); @@ -98,7 +98,7 @@ describe("WithFacility", () => { }, facilities: [{ id: "1", name: "Facility 1" }], }); - component = render( + render( App @@ -130,7 +130,7 @@ describe("WithFacility", () => { { id: "2", name: "Facility 2" }, ], }); - component = render( + render( App @@ -140,15 +140,15 @@ describe("WithFacility", () => { }); it("should show the facility selection screen", () => { - expect(component.container.firstChild).toMatchSnapshot(); + expect( + screen.getByText("Please select the testing facility", { exact: false }) + ).toBeInTheDocument(); }); describe("On facility select", () => { beforeEach(async () => { const options = await screen.findAllByRole("button"); - await waitFor(() => { - userEvent.click(options[0]); - }); + userEvent.click(options[0]); }); it("should show the app", async () => { const renderedApp = await screen.findByText("App"); @@ -214,9 +214,13 @@ describe("WithFacility", () => { ); - await act(async () => { - await screen.findAllByText("Welcome to SimpleReport", { exact: false }); - }); + expect( + ( + await screen.findAllByText("Welcome to SimpleReport", { + exact: false, + }) + )[0] + ).toBeInTheDocument(); }); it("should render the facility form", async () => { diff --git a/frontend/src/app/facilitySelect/__snapshots__/FacilitySelect.test.tsx.snap b/frontend/src/app/facilitySelect/__snapshots__/FacilitySelect.test.tsx.snap deleted file mode 100644 index 193d51de8f..0000000000 --- a/frontend/src/app/facilitySelect/__snapshots__/FacilitySelect.test.tsx.snap +++ /dev/null @@ -1,64 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`FacilitySelect should render with a value 1`] = ` -
-
-
-
-
-
-

- SimpleReport -

-
- Organization Name -
-
-
-
-

- Welcome, - Kim Mendoza -

-

- Please select the testing facility where you are working today. -

- - -
-
-
-
-
-`; diff --git a/frontend/src/app/facilitySelect/__snapshots__/WithFacility.test.tsx.snap b/frontend/src/app/facilitySelect/__snapshots__/WithFacility.test.tsx.snap deleted file mode 100644 index 050c312933..0000000000 --- a/frontend/src/app/facilitySelect/__snapshots__/WithFacility.test.tsx.snap +++ /dev/null @@ -1,112 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`WithFacility With two facilities should show the facility selection screen 1`] = ` -
-
-
-
-
-
-

- SimpleReport -

-
- Organization Name -
-
-
-
-

- Welcome, - Kim Mendoza -

-

- Please select the testing facility where you are working today. -

- - -
-
-
-
-
-`; - -exports[`WithFacility With zero facilities should notify user to contact an admin 1`] = ` -
-
-
-
-
-
-

- SimpleReport -

-
- Organization Name -
-
-
-
-

- Welcome, - Kim Mendoza -

-

- You do not have access to any facilities at this time. -

-

- Ask an administrator to assign you access, then try logging in again. -

-
-
-
-
-
-`; diff --git a/frontend/src/app/login/MfaAuthenticationApp/MfaAuthenticationApp.test.tsx b/frontend/src/app/login/MfaAuthenticationApp/MfaAuthenticationApp.test.tsx index 1748397c41..1c08505d7c 100644 --- a/frontend/src/app/login/MfaAuthenticationApp/MfaAuthenticationApp.test.tsx +++ b/frontend/src/app/login/MfaAuthenticationApp/MfaAuthenticationApp.test.tsx @@ -20,6 +20,6 @@ describe("Submit Email MFA", () => { it("requires a security code", () => { userEvent.click(screen.getByText("Submit")); const error = screen.getByRole("alert"); - expect(error.textContent).toEqual("Error: Enter your security code"); + expect(error).toHaveTextContent("Error: Enter your security code"); }); }); diff --git a/frontend/src/app/login/MfaPhone/MfaPhone.test.tsx b/frontend/src/app/login/MfaPhone/MfaPhone.test.tsx index f9e4eb5f9f..70813ddd13 100644 --- a/frontend/src/app/login/MfaPhone/MfaPhone.test.tsx +++ b/frontend/src/app/login/MfaPhone/MfaPhone.test.tsx @@ -20,6 +20,6 @@ describe("Submit Email MFA", () => { it("requires a security code", () => { userEvent.click(screen.getByText("Submit")); const error = screen.getByRole("alert"); - expect(error.textContent).toEqual("Error: Enter your security code"); + expect(error).toHaveTextContent("Error: Enter your security code"); }); }); diff --git a/frontend/src/app/patients/AddPatient.stories.tsx b/frontend/src/app/patients/AddPatient.stories.tsx index 9e16181001..73a49aca0c 100644 --- a/frontend/src/app/patients/AddPatient.stories.tsx +++ b/frontend/src/app/patients/AddPatient.stories.tsx @@ -19,7 +19,7 @@ export default { argTypes: {}, } as Meta; -const Template: Story = (args) => ( +const Template: Story = (_args) => ( diff --git a/frontend/src/app/patients/AddPatient.test.tsx b/frontend/src/app/patients/AddPatient.test.tsx index 1133a05f90..870d0532cc 100644 --- a/frontend/src/app/patients/AddPatient.test.tsx +++ b/frontend/src/app/patients/AddPatient.test.tsx @@ -1,15 +1,15 @@ import { render, screen, - fireEvent, - cleanup, within, + waitForElementToBeRemoved, + waitFor, } from "@testing-library/react"; import { MockedProvider } from "@apollo/client/testing"; import { Provider } from "react-redux"; import configureStore from "redux-mock-store"; -import { act } from "react-dom/test-utils"; import { MemoryRouter, Route } from "react-router"; +import userEvent from "@testing-library/user-event"; import AddPatient, { ADD_PATIENT, PATIENT_EXISTS } from "./AddPatient"; @@ -33,21 +33,28 @@ jest.mock("../utils/smartyStreets", () => ({ const fillOutForm = ( inputs: { [label: string]: string }, + dropdowns: { [label: string]: string }, inputGroups: { [legend: string]: { label: string; value: string; exact?: boolean }; } ) => { Object.entries(inputs).forEach(([label, value]) => { - fireEvent.change( + userEvent.type( screen.getByLabelText(label, { exact: false, }), - { - target: { value }, - } + value ); }); - Object.entries(inputGroups).forEach(([legend, { label, value, exact }]) => { + Object.entries(dropdowns).forEach(([label, value]) => { + userEvent.selectOptions( + screen.getByLabelText(label, { + exact: false, + }), + [value] + ); + }); + Object.entries(inputGroups).forEach(([legend, { label, exact }]) => { const fieldset = screen .getByText(legend, { exact: false, @@ -56,19 +63,15 @@ const fillOutForm = ( if (fieldset === null) { throw Error(`Unable to corresponding fieldset for ${legend}`); } - fireEvent.click( + userEvent.click( within(fieldset).getByLabelText(label, { exact: exact || false, - }), - { - target: { value }, - } + }) ); }); }; describe("AddPatient", () => { - afterEach(cleanup); describe("No facility selected", () => { beforeEach(() => { render( @@ -86,7 +89,7 @@ describe("AddPatient", () => { screen.queryByText("Add new person", { exact: false, }) - ).toBeNull(); + ).not.toBeInTheDocument(); }); it("shows a 'No facility selected' message", async () => { expect( @@ -98,7 +101,7 @@ describe("AddPatient", () => { }); describe("happy path", () => { - beforeEach(() => { + beforeEach(async () => { const mocks = [ { request: { @@ -192,7 +195,7 @@ describe("AddPatient", () => { - +

Patients!

} /> { }); it("shows the form title", async () => { expect( - await screen.queryAllByText("Add new person", { exact: false })[0] + (await screen.findAllByText("Add new person", { exact: false }))[0] ).toBeInTheDocument(); }); describe("Choosing a country", () => { it("should show the state and zip code inputs for USA", async () => { - fillOutForm( - { - "First Name": "Alice", - "Last Name": "Hamilton", - Facility: mockFacilityID, - "Date of birth": "1970-09-22", - "Primary phone number": "617-432-1000", - "Email address": "foo@bar.org", - Country: "USA", - "Street address 1": "25 Shattuck St", - City: "Vancouver", - }, - { - "Phone type": { - label: "Mobile", - value: "MOBILE", - exact: true, - }, - "Would you like to receive your results via text message": { - label: "Yes", - value: "SMS", - exact: false, - }, - } + userEvent.selectOptions( + screen.getByLabelText("Country", { exact: false }), + "USA" ); - expect(await screen.queryByText("State")).toBeInTheDocument(); - expect(await screen.queryByText("ZIP code")).toBeInTheDocument(); + expect(await screen.findByText("State")).toBeInTheDocument(); + expect(await screen.findByText("ZIP code")).toBeInTheDocument(); }); it("should hide the state and zip code inputs for non-US countries", async () => { - fillOutForm( - { - "First Name": "Alice", - "Last Name": "Hamilton", - Facility: mockFacilityID, - "Date of birth": "1970-09-22", - "Primary phone number": "617-432-1000", - "Email address": "foo@bar.org", - Country: "CAN", - "Street address 1": "25 Shattuck St", - City: "Vancouver", - }, - { - "Phone type": { - label: "Mobile", - value: "MOBILE", - exact: true, - }, - "Would you like to receive your results via text message": { - label: "Yes", - value: "SMS", - exact: false, - }, - } + userEvent.selectOptions( + screen.getByLabelText("Country", { exact: false }), + "CAN" ); - expect(await screen.queryByText("State")).not.toBeInTheDocument(); - expect(await screen.queryByText("ZIP code")).not.toBeInTheDocument(); + expect(screen.queryByText("State")).not.toBeInTheDocument(); + expect(screen.queryByText("ZIP code")).not.toBeInTheDocument(); }); }); - describe("All required fields entered", () => { - beforeEach(async () => { + describe("All required fields entered and submitting address verification", () => { + it("redirects to the person tab", async () => { fillOutForm( { "First Name": "Alice", "Last Name": "Hamilton", - Facility: mockFacilityID, "Date of birth": "1970-09-22", "Primary phone number": "617-432-1000", "Email address": "foo@bar.org", "Street address 1": "25 Shattuck St", City: "Boston", - State: "MA", + "ZIP code": "02115", }, + { Facility: mockFacilityID, State: "MA", Country: "USA" }, { "Phone type": { label: "Mobile", @@ -298,44 +259,34 @@ describe("AddPatient", () => { }, } ); - await act(async () => { - fireEvent.click( - screen.queryAllByText("Save Changes", { - exact: false, - })[0] - ); - }); - }); - it("show the address validation modal", async () => { - await screen.findByText(`Address Validation`, { + userEvent.click( + screen.queryAllByText("Save Changes", { + exact: false, + })[0] + ); + expect( + await screen.findByText("Address validation", { + exact: false, + }) + ).toBeInTheDocument(); + const modal = screen.getByRole("dialog", { exact: false, }); - }); - describe("Submitting Address Verification", () => { - beforeEach(async () => { - const modal = screen.getByRole("dialog", { - exact: false, - }); - fireEvent.click( - within(modal).getByLabelText("Use address as entered", { - exact: false, - }), - { - target: { value: "userAddress" }, - } - ); - await act(async () => { - fireEvent.click( - within(modal).getByText("Save changes", { - exact: false, - }) - ); - }); - }); - it("redirects to the person tab", () => { - expect(screen.getByText("Patients!")).toBeInTheDocument(); - }); + userEvent.click( + within(modal).getByLabelText("Use address as entered", { + exact: false, + }) + ); + userEvent.click( + within(modal).getByText("Save changes", { + exact: false, + }) + ); + await waitForElementToBeRemoved(() => + screen.queryAllByText("Saving...") + ); + expect(screen.getByText("Patients!")).toBeInTheDocument(); }); }); @@ -353,70 +304,32 @@ describe("AddPatient", () => { expect(facilityInput.value).toBe(""); }); it("updates its selection on change", async () => { - fireEvent.change(facilityInput, { - target: { value: mockFacilityID }, - }); + userEvent.selectOptions(facilityInput, [mockFacilityID]); expect(facilityInput.value).toBe(mockFacilityID); }); }); describe("With student ID", () => { it("allows student ID to be entered", async () => { - fillOutForm( - { - "First Name": "Alice", - "Last Name": "Hamilton", - Facility: mockFacilityID, - "Date of birth": "1970-09-22", - "Primary phone number": "617-432-1000", - "Street address 1": "25 Shattuck St", - City: "Boston", - State: "MA", - "ZIP code": "02115", - }, - { - "Phone type": { - label: "Mobile", - value: "MOBILE", - exact: true, - }, - "Are you a resident in a congregate living setting": { - label: "No", - value: "No", - exact: true, - }, - "Are you a health care worker": { - label: "Yes", - value: "Yes", - exact: true, - }, - } - ); - - fireEvent.change(screen.getByLabelText("Role"), { - target: { value: "STUDENT" }, - }); + userEvent.selectOptions(screen.getByLabelText("Role"), "STUDENT"); expect(await screen.findByText("Student ID")).toBeInTheDocument(); }); }); describe("saving changes and starting a test", () => { - beforeEach(async () => { - await new Promise((resolve) => setTimeout(resolve, 0)); + it("redirects to the queue with a patient id and selected facility id", async () => { fillOutForm( { "First Name": "Alice", "Last Name": "Hamilton", - Facility: mockFacilityID, "Date of birth": "1970-09-22", "Primary phone number": "617-432-1000", "Email address": "foo@bar.org", "Street address 1": "25 Shattuck St", - Country: "USA", City: "Boston", - State: "MA", "ZIP code": "02115", }, + { Facility: mockFacilityID, State: "MA", Country: "USA" }, { "Phone type": { label: "Mobile", @@ -430,36 +343,34 @@ describe("AddPatient", () => { }, } ); - await act(async () => { - fireEvent.click( - screen.queryAllByText("Save and start test", { - exact: false, - })[0] - ); - }); + userEvent.click( + screen.queryAllByText("Save and start test", { + exact: false, + })[0] + ); + expect( + await screen.findByText("Address validation", { + exact: false, + }) + ).toBeInTheDocument(); const modal = screen.getByRole("dialog", { exact: false, }); - fireEvent.click( + userEvent.click( within(modal).getByLabelText("Use address as entered", { exact: false, - }), - { - target: { value: "userAddress" }, - } + }) + ); + userEvent.click( + within(modal).getByText("Save changes", { + exact: false, + }) + ); + await waitForElementToBeRemoved(() => + screen.queryAllByText("Saving...") ); - await act(async () => { - fireEvent.click( - within(modal).getByText("Save changes", { - exact: false, - }) - ); - }); - }); - - it("redirects to the queue with a patient id and selected facility id", () => { expect( screen.getByText("Testing Queue!", { exact: false }) ).toBeInTheDocument(); @@ -471,9 +382,8 @@ describe("AddPatient", () => { }); describe("when attempting to create an existing patient ", () => { - let patientExistsMockWasCalled = false; - - it("performs GraphQL query when all identifying data fields have been entered", async () => { + it("does not open modal if no patient with matching data exists", async () => { + let patientExistsMock = jest.fn(); const mocks = [ { request: { @@ -487,8 +397,7 @@ describe("AddPatient", () => { }, }, result: () => { - patientExistsMockWasCalled = true; - + patientExistsMock(); return { data: { patientExists: false, @@ -513,75 +422,25 @@ describe("AddPatient", () => { { "First Name": "Alice", "Last Name": "Hamilton", - Facility: mockFacilityID, "Date of birth": "1970-09-22", - "ZIP code": "02115", }, + { Facility: mockFacilityID }, {} ); - const zip = await screen.findByLabelText("ZIP code", { - exact: false, - }); - - fireEvent.blur(zip); - - await new Promise((resolve) => setTimeout(resolve, 1000)); - - expect(patientExistsMockWasCalled).toBe(true); - }); - - it("does not open modal if no patient with matching data exists", async () => { - const mocks = [ - { - request: { - query: PATIENT_EXISTS, - variables: { - firstName: "Alice", - lastName: "Hamilton", - birthDate: "1970-09-22", - zipCode: "02115", - facilityId: mockFacilityID, - }, - }, - result: { - data: { - patientExists: false, - }, - }, - }, - ]; - - render( - - - - -

Patients!

} /> -
-
-
- ); - - fillOutForm( - { - "First Name": "Alice", - "Last Name": "Hamilton", - Facility: mockFacilityID, - "Date of birth": "1970-09-22", - "ZIP code": "02115", - }, - {} + // The duplicate patient check is triggered on-blur from one of the identifying data fields + userEvent.type( + screen.getByLabelText("ZIP code", { exact: false }), + "02115" ); + userEvent.tab(); - const zip = await screen.findByLabelText("ZIP code", { - exact: false, + await waitFor(() => { + expect(patientExistsMock).toHaveBeenCalledTimes(1); }); - fireEvent.blur(zip); - expect( - screen.queryByText("You already have a profile at", { + screen.queryByText("This patient is already registered", { exact: false, }) ).not.toBeInTheDocument(); @@ -623,27 +482,18 @@ describe("AddPatient", () => { { "First Name": "Alice", "Last Name": "Hamilton", - Facility: mockFacilityID, "Date of birth": "1970-09-22", - "ZIP code": "02115", }, + { Facility: mockFacilityID }, {} ); // The duplicate patient check is triggered on-blur from one of the identifying data fields - const zip = await screen.findByLabelText("ZIP code", { - exact: false, - }); - - act(() => { - fireEvent.change(zip, { - target: { - value: "02115", - }, - }); - }); - - fireEvent.blur(zip); + userEvent.type( + screen.getByLabelText("ZIP code", { exact: false }), + "02115" + ); + userEvent.tab(); expect( await screen.findByText("This patient is already registered", { diff --git a/frontend/src/app/patients/Components/ManageEmails.test.tsx b/frontend/src/app/patients/Components/ManageEmails.test.tsx index f9082a6885..09a7ecea1d 100644 --- a/frontend/src/app/patients/Components/ManageEmails.test.tsx +++ b/frontend/src/app/patients/Components/ManageEmails.test.tsx @@ -119,9 +119,7 @@ describe("ManageEmails", () => { const addButton = screen.getByText("Add another email address", { exact: false, }); - await waitFor(() => { - userEvent.click(addButton); - }); + userEvent.click(addButton); const second = (await screen.findAllByText("Email address"))[1]; userEvent.type(second, "foo@bar.com"); userEvent.click( diff --git a/frontend/src/app/patients/Components/ManageEmails.tsx b/frontend/src/app/patients/Components/ManageEmails.tsx index c1f2ca5fac..585bd1e896 100644 --- a/frontend/src/app/patients/Components/ManageEmails.tsx +++ b/frontend/src/app/patients/Components/ManageEmails.tsx @@ -15,7 +15,6 @@ interface Props { const ManageEmails: React.FC = ({ emails, - patient, updateEmails, emailValidator, }) => { diff --git a/frontend/src/app/patients/Components/ManagePhoneNumbers.tsx b/frontend/src/app/patients/Components/ManagePhoneNumbers.tsx index 18cc0857ca..4784fa91d4 100644 --- a/frontend/src/app/patients/Components/ManagePhoneNumbers.tsx +++ b/frontend/src/app/patients/Components/ManagePhoneNumbers.tsx @@ -203,7 +203,7 @@ const ManagePhoneNumbers: React.FC = ({ formObject={phoneNumber} validate={(field) => validateField(idx, field)} getValidationStatus={() => validationStatus(idx, "number")} - onChange={(field) => (value) => onPhoneNumberChange(idx, value)} + onChange={(_) => (value) => onPhoneNumberChange(idx, value)} errors={errors[idx] || {}} /> {!isPrimary && ( diff --git a/frontend/src/app/patients/EditPatient.test.tsx b/frontend/src/app/patients/EditPatient.test.tsx index 201103ac74..caaf4d411a 100644 --- a/frontend/src/app/patients/EditPatient.test.tsx +++ b/frontend/src/app/patients/EditPatient.test.tsx @@ -2,7 +2,6 @@ import { render, screen, fireEvent, - cleanup, within, waitFor, } from "@testing-library/react"; @@ -10,7 +9,6 @@ import userEvent from "@testing-library/user-event"; import { MockedProvider } from "@apollo/client/testing"; import { Provider } from "react-redux"; import configureStore from "redux-mock-store"; -import { act } from "react-dom/test-utils"; import { MemoryRouter } from "react-router"; import { ToastContainer } from "react-toastify"; @@ -23,8 +21,6 @@ jest.mock("@trussworks/react-uswds", () => ({ const mockStore = configureStore([]); describe("EditPatient", () => { - afterEach(cleanup); - const mockFacilityID = "b0d2041f-93c9-4192-b19a-dd99c0044a7e"; const mockPatientID = "555e8a40-0f95-458e-a038-6b500a0fc2ad"; const store = mockStore({ @@ -48,7 +44,7 @@ describe("EditPatient", () => { }); it("shows loading text", async () => { expect( - await screen.queryAllByText("loading...", { exact: false })[0] + screen.getAllByText("loading...", { exact: false })[0] ).toBeInTheDocument(); }); }); @@ -125,9 +121,9 @@ describe("EditPatient", () => { ); - await act(async () => { - await screen.findAllByText("Franecki, Eugenia", { exact: false }); - }); + expect( + (await screen.findAllByText("Franecki, Eugenia", { exact: false }))[0] + ).toBeInTheDocument(); }); it("populates primary phone number field with patient `telephone`", () => { @@ -147,13 +143,11 @@ describe("EditPatient", () => { }); it("displays a validation failure alert if phone type not entered", async () => { - await act(async () => { - userEvent.click( - screen.queryAllByText("Add another number", { - exact: false, - })[0] - ); - }); + userEvent.click( + screen.queryAllByText("Add another number", { + exact: false, + })[0] + ); // Do not enter phone type for additional number const number = screen.getAllByLabelText("Additional phone number", { @@ -164,9 +158,7 @@ describe("EditPatient", () => { target: { value: "6318675309" }, }); - await waitFor(() => { - userEvent.click(screen.getAllByText("Save changes")[0]); - }); + userEvent.click(screen.getAllByText("Save changes")[0]); expect( await screen.findByText("Phone type is required", { @@ -238,14 +230,14 @@ describe("EditPatient", () => {
); - await act(async () => { - await screen.findAllByText("Franecki, Eugenia", { exact: false }); - }); + expect( + (await screen.findAllByText("Franecki, Eugenia", { exact: false }))[0] + ).toBeInTheDocument(); }); it("shows the form title", () => { expect( - screen.queryAllByText("Franecki, Eugenia", { exact: false })[0] + screen.getAllByText("Franecki, Eugenia", { exact: false })[0] ).toBeInTheDocument(); }); @@ -334,9 +326,9 @@ describe("EditPatient", () => {
); - await act(async () => { - await screen.findAllByText("Franecki, Eugenia", { exact: false }); - }); + expect( + (await screen.findAllByText("Franecki, Eugenia", { exact: false }))[0] + ).toBeInTheDocument(); }); it("shows prefer not to answer options", () => { @@ -392,9 +384,9 @@ describe("EditPatient", () => { // Error message on bad value fireEvent.change(name, { target: { value: "" } }); fireEvent.blur(name); - await waitFor(() => { - expect(screen.getByText("First name is required")).toBeInTheDocument(); - }); + expect( + await screen.findByText("First name is required") + ).toBeInTheDocument(); // No error message on good value fireEvent.change(name, { target: { value: "James" } }); fireEvent.blur(name); @@ -423,11 +415,9 @@ describe("EditPatient", () => { ); }); it("renders", async () => { - await waitFor(() => { - expect( - screen.queryByText("Franecki, Eugenia", { exact: false }) - ).toBeInTheDocument(); - }); + expect( + await screen.findByText("Franecki, Eugenia", { exact: false }) + ).toBeInTheDocument(); }); }); describe("EditPatientContainer", () => { diff --git a/frontend/src/app/signUp/IdentityVerification/Consent.test.tsx b/frontend/src/app/signUp/IdentityVerification/Consent.test.tsx index 06a2045b04..286af71147 100644 --- a/frontend/src/app/signUp/IdentityVerification/Consent.test.tsx +++ b/frontend/src/app/signUp/IdentityVerification/Consent.test.tsx @@ -27,7 +27,7 @@ describe("Consent", () => { ); }); it("initializes with the submit button enabled", () => { - expect(screen.getByText("I agree")).not.toHaveAttribute("disabled"); + expect(screen.getByText("I agree")).toBeEnabled(); }); it("redirects to sign-up page when it doesnt get org id and user info", () => { diff --git a/frontend/src/app/signUp/IdentityVerification/PersonalDetailsForm.test.tsx b/frontend/src/app/signUp/IdentityVerification/PersonalDetailsForm.test.tsx index a6d0fcb4da..aa7195e7e9 100644 --- a/frontend/src/app/signUp/IdentityVerification/PersonalDetailsForm.test.tsx +++ b/frontend/src/app/signUp/IdentityVerification/PersonalDetailsForm.test.tsx @@ -1,4 +1,4 @@ -import { render, screen, fireEvent, act } from "@testing-library/react"; +import { render, screen, fireEvent, waitFor } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import PersonalDetailsForm from "./PersonalDetailsForm"; @@ -28,7 +28,7 @@ describe("PersonalDetailsForm", () => { }); it("initializes with the submit button disabled", () => { - expect(screen.getByText("Submit")).toHaveAttribute("disabled"); + expect(screen.getByText("Submit")).toBeDisabled(); }); describe("Filling out the form", () => { @@ -40,61 +40,43 @@ describe("PersonalDetailsForm", () => { }); it("enables the submit button", () => { - expect(screen.getByText("Submit")).not.toHaveAttribute("disabled"); + expect(screen.getByText("Submit")).toBeEnabled(); }); describe("focusing and not adding a value", () => { - beforeEach(async () => { - await act(async () => { - await screen - .getByLabelText("Phone number *", { exact: false }) - .focus(); - await screen - .getByLabelText("Street address 1", { exact: false }) - .focus(); - }); - }); - it("shows a single error", () => { + it("shows a single error", async () => { + screen.getByLabelText("Phone number *", { exact: false }).focus(); + screen.getByLabelText("Street address 1", { exact: false }).focus(); expect( - screen.getByText("A valid phone number is required") + await screen.findByText("A valid phone number is required") ).toBeInTheDocument(); }); }); describe("On submitting with an invalid phone number", () => { - beforeEach(async () => { - await act(async () => { - userEvent.type( - screen.getByLabelText("Phone number", { exact: false }), - "123" - ); - userEvent.click(screen.getByText("Submit")); - }); - }); - it("shows an error", () => { + it("shows an error", async () => { + userEvent.type( + screen.getByLabelText("Phone number", { exact: false }), + "123" + ); + userEvent.click(screen.getByText("Submit")); expect( - screen.getByText("A valid phone number is required") + await screen.findByText("A valid phone number is required") ).toBeInTheDocument(); }); }); describe("On submitting an invalid street address 1", () => { - beforeEach(async () => { - await act(async () => { - userEvent.type( - screen.getByLabelText("Street address 1", { exact: false }), - "111 greendale dr," - ); - }); - await act(async () => { - userEvent.click(screen.getByText("Submit")); - }); - }); - it("shows an error", () => { + it("shows an error", async () => { + userEvent.type( + screen.getByLabelText("Street address 1", { exact: false }), + "111 greendale dr," + ); + userEvent.click(screen.getByText("Submit")); expect( - screen.getByText("A valid street address is required") + await screen.findByText("A valid street address is required") ).toBeInTheDocument(); }); }); describe("On clicking an invalid date of birth and submitting", () => { - beforeEach(async () => { + it("shows an error", async () => { userEvent.click(screen.getByTestId("date-picker-button")); const nextMonthButton = screen.getByTestId("next-month"); expect(nextMonthButton).toHaveClass( @@ -104,18 +86,14 @@ describe("PersonalDetailsForm", () => { const dateButton = screen.getByText("15"); expect(dateButton).toHaveClass("usa-date-picker__calendar__date"); userEvent.click(dateButton); - await act(async () => { - userEvent.click(screen.getByText("Submit")); - }); - }); - it("shows an error", () => { + userEvent.click(screen.getByText("Submit")); expect( - screen.getByText("A valid date of birth is required") + await screen.findByText("A valid date of birth is required") ).toBeInTheDocument(); }); }); describe("On clicking a valid date of birth and submitting", () => { - beforeEach(async () => { + it("shows an error", async () => { userEvent.click(screen.getByTestId("date-picker-button")); const previousMonthButton = screen.getByTestId("previous-month"); expect(previousMonthButton).toHaveClass( @@ -125,64 +103,48 @@ describe("PersonalDetailsForm", () => { const dateButton = screen.getByText("15"); expect(dateButton).toHaveClass("usa-date-picker__calendar__date"); userEvent.click(dateButton); - await act(async () => { - userEvent.click(screen.getByText("Submit")); + userEvent.click(screen.getByText("Submit")); + await waitFor(() => { + expect( + screen.queryByText("A valid date of birth is required") + ).not.toBeInTheDocument(); }); }); - it("shows an error", () => { - expect( - screen.queryByText("A valid date of birth is required") - ).not.toBeInTheDocument(); - }); }); describe("On submitting an invalid street address 2", () => { - beforeEach(async () => { - await act(async () => { - userEvent.type( - screen.getByLabelText("Street address 2", { exact: false }), - "111 greendale dr," - ); - }); - await act(async () => { - userEvent.click(screen.getByText("Submit")); - }); - }); - it("shows an error", () => { + it("shows an error", async () => { + userEvent.type( + screen.getByLabelText("Street address 2", { exact: false }), + "111 greendale dr," + ); + userEvent.click(screen.getByText("Submit")); expect( - screen.getByText("Street 2 contains invalid symbols") + await screen.findByText("Street 2 contains invalid symbols") ).toBeInTheDocument(); }); }); describe("On submitting an invalid zip code", () => { - beforeEach(async () => { - await act(async () => { - userEvent.type( - screen.getByLabelText("ZIP code", { exact: false }), - "1234" - ); - }); - await act(async () => { - userEvent.click(screen.getByText("Submit")); - }); - }); - it("shows an error", () => { + it("shows an error", async () => { + userEvent.type( + screen.getByLabelText("ZIP code", { exact: false }), + "1234" + ); + userEvent.click(screen.getByText("Submit")); expect( - screen.getByText("A valid ZIP code is required") + await screen.findByText("A valid ZIP code is required") ).toBeInTheDocument(); }); }); describe("On submitting an incomplete form", () => { - beforeEach(async () => { - await act(async () => { - fillInText("Email", "bob@bob.bob"); - userEvent.click(screen.getByText("Submit")); + it("shows an error", async () => { + fillInText("Email", "bob@bob.bob"); + userEvent.click(screen.getByText("Submit")); + await waitFor(() => { + expect( + screen.queryAllByText("is required", { exact: false }).length + ).toBe(6); }); }); - it("shows an error", () => { - expect( - screen.queryAllByText("is required", { exact: false }).length - ).toBe(6); - }); }); }); @@ -201,14 +163,12 @@ describe("PersonalDetailsForm", () => { }); describe("On submit", () => { - beforeEach(async () => { - await act(async () => { - userEvent.click(screen.getByText("Submit")); + it("does not shows an error", async () => { + userEvent.click(screen.getByText("Submit")); + await waitFor(() => { + expect(screen.queryAllByText("is required").length).toBe(0); }); }); - it("does not shows an error", () => { - expect(screen.queryAllByText("is required").length).toBe(0); - }); }); }); }); diff --git a/frontend/src/app/signUp/IdentityVerification/QuestionsForm.test.tsx b/frontend/src/app/signUp/IdentityVerification/QuestionsForm.test.tsx index 306c0387a1..62a0f55629 100644 --- a/frontend/src/app/signUp/IdentityVerification/QuestionsForm.test.tsx +++ b/frontend/src/app/signUp/IdentityVerification/QuestionsForm.test.tsx @@ -1,4 +1,4 @@ -import { render, screen, act } from "@testing-library/react"; +import { render, screen, waitFor } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { exampleQuestionSet } from "./constants"; @@ -22,78 +22,101 @@ describe("QuestionsForm", () => { ); }); it("initializes with the submit button disabled", () => { - expect(screen.getByText("Submit")).toHaveAttribute("disabled"); + expect(screen.getByText("Submit")).toBeDisabled(); }); it("initializes with a counter and starts counting down", async () => { expect(screen.getByText("5:00")).toBeInTheDocument(); expect(await screen.findByText("4:59")).toBeInTheDocument(); }); describe("One field entered", () => { - beforeEach(() => { - userEvent.click(screen.getByLabelText("2002", { exact: false })); - }); it("enables the submit button", () => { - expect(screen.getByText("Submit")).not.toHaveAttribute("disabled"); + userEvent.click(screen.getByLabelText("2002", { exact: false })); + expect(screen.getByText("Submit")).toBeEnabled(); }); describe("focusing and not adding a value", () => { - beforeEach(async () => { - await act(async () => { - await screen.getByLabelText("ELECTRICIAN", { exact: false }).focus(); - await screen.getByText("Submit", { exact: false }).focus(); + it("shows a single error", async () => { + userEvent.click(screen.getByLabelText("2002", { exact: false })); + screen.getByLabelText("ELECTRICIAN", { exact: false }).focus(); + screen.getByText("Submit", { exact: false }).focus(); + await waitFor(() => { + expect(screen.queryAllByText("This field is required").length).toBe( + 1 + ); }); }); - it("shows a single error", () => { - expect(screen.queryAllByText("This field is required").length).toBe(1); - }); }); describe("On submit", () => { - beforeEach(async () => { - await act(async () => { - await userEvent.click( - screen.queryAllByText("Submit", { - exact: false, - })[0] + it("shows an error", async () => { + userEvent.click(screen.getByLabelText("2002", { exact: false })); + userEvent.click( + screen.queryAllByText("Submit", { + exact: false, + })[0] + ); + await waitFor(() => { + expect(screen.queryAllByText("This field is required").length).toBe( + 4 ); }); }); - it("shows an error", () => { - expect(screen.queryAllByText("This field is required").length).toBe(4); - }); - it("does not call the onSubmit callback", () => { - expect(onSubmit).not.toHaveBeenCalled(); + it("does not call the onSubmit callback", async () => { + userEvent.click(screen.getByLabelText("2002", { exact: false })); + userEvent.click( + screen.queryAllByText("Submit", { + exact: false, + })[0] + ); + await waitFor(() => { + expect(onSubmit).not.toHaveBeenCalled(); + }); }); }); }); describe("Completed form", () => { - beforeEach(() => { - userEvent.click(screen.getByLabelText("2002", { exact: false })); - userEvent.click( - screen.getByLabelText("OPTICIAN / OPTOMETRIST", { exact: false }) - ); - userEvent.click( - screen.getByLabelText("MID AMERICA MORTGAGE", { exact: false }) - ); - userEvent.click(screen.getByLabelText("TWO", { exact: false })); - userEvent.click( - screen.getByLabelText("AGUA DULCE HIGH SCHOOL", { exact: false }) - ); - }); - describe("On submit", () => { - beforeEach(async () => { - await act(async () => { - await userEvent.click( - screen.queryAllByText("Submit", { - exact: false, - })[0] + it("does not show an error", async () => { + userEvent.click(screen.getByLabelText("2002", { exact: false })); + userEvent.click( + screen.getByLabelText("OPTICIAN / OPTOMETRIST", { exact: false }) + ); + userEvent.click( + screen.getByLabelText("MID AMERICA MORTGAGE", { exact: false }) + ); + userEvent.click(screen.getByLabelText("TWO", { exact: false })); + userEvent.click( + screen.getByLabelText("AGUA DULCE HIGH SCHOOL", { exact: false }) + ); + userEvent.click( + screen.queryAllByText("Submit", { + exact: false, + })[0] + ); + await waitFor(() => { + expect(screen.queryAllByText("This field is required").length).toBe( + 0 ); }); }); - it("does not show an error", () => { - expect(screen.queryAllByText("This field is required").length).toBe(0); - }); - it("calls the onSubmit callback", () => { - expect(onSubmit).toHaveBeenCalled(); + it("calls the onSubmit callback", async () => { + userEvent.click(screen.getByLabelText("2002", { exact: false })); + userEvent.click( + screen.getByLabelText("OPTICIAN / OPTOMETRIST", { exact: false }) + ); + userEvent.click( + screen.getByLabelText("MID AMERICA MORTGAGE", { exact: false }) + ); + userEvent.click(screen.getByLabelText("TWO", { exact: false })); + userEvent.click( + screen.getByLabelText("AGUA DULCE HIGH SCHOOL", { exact: false }) + ); + userEvent.click( + screen.queryAllByText("Submit", { + exact: false, + })[0] + ); + await waitFor(() => { + expect(onSubmit).toHaveBeenCalled(); + }); }); }); }); diff --git a/frontend/src/app/signUp/IdentityVerification/QuestionsFormContainer.test.tsx b/frontend/src/app/signUp/IdentityVerification/QuestionsFormContainer.test.tsx index 071c267e96..4536cab175 100644 --- a/frontend/src/app/signUp/IdentityVerification/QuestionsFormContainer.test.tsx +++ b/frontend/src/app/signUp/IdentityVerification/QuestionsFormContainer.test.tsx @@ -1,4 +1,10 @@ -import { act, fireEvent, render, screen } from "@testing-library/react"; +import { + fireEvent, + render, + screen, + waitForElementToBeRemoved, +} from "@testing-library/react"; +import userEvent from "@testing-library/user-event"; import QuestionsFormContainer from "./QuestionsFormContainer"; import { initPersonalDetails } from "./utils"; @@ -36,14 +42,15 @@ describe("QuestionsFormContainer", () => { beforeEach(async () => { personalDetails = initPersonalDetails("foo", "Bob", "Bill", "Martínez"); personalDetails.phoneNumber = "530/867/5309 ext. 222"; - await act(async () => { - render( - - ); - }); + render( + + ); + await waitForElementToBeRemoved(() => + screen.queryByText("Submitting ID verification details …") + ); }); it("show the user that the page is loading", () => { personalDetails.orgExternalId = "slow"; @@ -104,15 +111,12 @@ describe("QuestionsFormContainer", () => { describe("On submit", () => { it("shows the success page if submitted with correct responses", async () => { - await act(async () => { - await fireEvent.click( - screen.queryAllByText("Submit", { - exact: false, - })[0] - ); - }); + const submitButton = screen.queryAllByText("Submit", { + exact: false, + })[0]; + userEvent.click(submitButton); expect( - screen.getByText( + await screen.findByText( "Congratulations, your identity has been verified successfully", { exact: false, @@ -124,17 +128,18 @@ describe("QuestionsFormContainer", () => { await fireEvent.click(screen.getByLabelText("2004", { exact: false }), { target: { value: "3" }, }); - await act(async () => { - await fireEvent.click( - screen.queryAllByText("Submit", { - exact: false, - })[0] - ); - }); - expect( - screen.getByText("Experian was unable to verify your identity", { + userEvent.click( + screen.queryAllByText("Submit", { exact: false, - }) + })[0] + ); + expect( + await screen.findByText( + "Experian was unable to verify your identity", + { + exact: false, + } + ) ).toBeInTheDocument(); }); }); @@ -149,24 +154,19 @@ describe("QuestionsFormContainer countdown", () => { it("redirects to failure page when countdown runs out", async () => { personalDetails = initPersonalDetails("foo", "Bob", "Bill", "Martínez"); personalDetails.phoneNumber = "530/867/5309 ext. 222"; - await act(async () => { - render( - - ); - expect(await screen.findByText("0:01")).toBeInTheDocument(); - expect( - await screen.findByText( - "Experian was unable to verify your identity.", - { - exact: false, - } - ) - ).toBeInTheDocument(); - }); + render( + + ); + expect(await screen.findByText("0:01")).toBeInTheDocument(); + expect( + await screen.findByText("Experian was unable to verify your identity.", { + exact: false, + }) + ).toBeInTheDocument(); }); afterEach(() => { jest.runOnlyPendingTimers(); diff --git a/frontend/src/app/signUp/Organization/OrganizationForm.test.tsx b/frontend/src/app/signUp/Organization/OrganizationForm.test.tsx index 90378bb13e..cd87ed388f 100644 --- a/frontend/src/app/signUp/Organization/OrganizationForm.test.tsx +++ b/frontend/src/app/signUp/Organization/OrganizationForm.test.tsx @@ -1,4 +1,4 @@ -import { act, render, screen } from "@testing-library/react"; +import { render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import OrganizationForm, { @@ -20,9 +20,7 @@ const getPhoneInput = () => screen.getByLabelText("Work phone number *"); const getSubmitButton = () => screen.getByText("Continue"); const fillInDropDown = (input: any, text: string) => - act(() => { - userEvent.selectOptions(input, [text]); - }); + userEvent.selectOptions(input, [text]); jest.mock("../SignUpApi", () => ({ SignUpApi: { @@ -81,12 +79,10 @@ describe("OrganizationForm", () => { it("displays form errors when submitting invalid input", async () => { fillInDropDown(getOrgStateDropdown(), "IN"); - await act(async () => { - await getSubmitButton().click(); - }); + getSubmitButton().click(); expect( - screen.getByText("Organization name is required") + await screen.findByText("Organization name is required") ).toBeInTheDocument(); expect( @@ -109,12 +105,10 @@ describe("OrganizationForm", () => { userEvent.type(getLastNameInput(), "Ever"); userEvent.type(getEmailInput(), "ever@greatest.com"); userEvent.type(getPhoneInput(), "8008675309"); - await act(async () => { - await getSubmitButton().click(); - }); + getSubmitButton().click(); expect( - screen.getByText("Redirected to /sign-up/identity-verification") + await screen.findByText("Redirected to /sign-up/identity-verification") ).toBeInTheDocument(); }); @@ -127,12 +121,10 @@ describe("OrganizationForm", () => { userEvent.type(getLastNameInput(), "Ever"); userEvent.type(getEmailInput(), "ever@greatest.com"); userEvent.type(getPhoneInput(), "8008675309"); - await act(async () => { - await getSubmitButton().click(); - }); + getSubmitButton().click(); expect( - screen.getByText( + await screen.findByText( "This organization already has a SimpleReport account. Please contact your organization administrator to request access.", { exact: false } ) @@ -148,12 +140,10 @@ describe("OrganizationForm", () => { userEvent.type(getLastNameInput(), "Ever"); userEvent.type(getEmailInput(), "duplicate@test.com"); userEvent.type(getPhoneInput(), "8008675309"); - await act(async () => { - await getSubmitButton().click(); - }); + getSubmitButton().click(); expect( - screen.getByText( + await screen.findByText( "This email address is already registered with SimpleReport.", { exact: false } ) @@ -169,12 +159,10 @@ describe("OrganizationForm", () => { userEvent.type(getLastNameInput(), "Ever"); userEvent.type(getEmailInput(), "admin@example.com"); userEvent.type(getPhoneInput(), "8008675309"); - await act(async () => { - await getSubmitButton().click(); - }); + getSubmitButton().click(); expect( - screen.getByText( + await screen.findByText( "Your organization is already registered with SimpleReport. To begin using it, schedule a time", { exact: false } ) @@ -190,12 +178,10 @@ describe("OrganizationForm", () => { userEvent.type(getLastNameInput(), "Ever"); userEvent.type(getEmailInput(), "admin@example.com"); userEvent.type(getPhoneInput(), "8008675309"); - await act(async () => { - await getSubmitButton().click(); - }); + getSubmitButton().click(); expect( - screen.getByText( + await screen.findByText( "Your organization is already registered with SimpleReport. Check your email for instructions on setting up your account.", { exact: false } ) @@ -211,12 +197,10 @@ describe("OrganizationForm", () => { userEvent.type(getLastNameInput(), "Ever"); userEvent.type(getEmailInput(), "admin@example.com"); userEvent.type(getPhoneInput(), "8008675309"); - await act(async () => { - await getSubmitButton().click(); - }); + getSubmitButton().click(); expect( - screen.getByText( + await screen.findByText( "An unexpected error occurred. Please resubmit this form", { exact: false } ) diff --git a/frontend/src/app/signUp/Organization/SignUpGoals.test.tsx b/frontend/src/app/signUp/Organization/SignUpGoals.test.tsx index f7e0758b1c..151f328b5a 100644 --- a/frontend/src/app/signUp/Organization/SignUpGoals.test.tsx +++ b/frontend/src/app/signUp/Organization/SignUpGoals.test.tsx @@ -7,7 +7,7 @@ describe("SignUpGoals", () => { render(); }); it("renders with the submit button enabled", () => { - expect(screen.getByText("Continue")).not.toHaveAttribute("disabled"); + expect(screen.getByText("Continue")).toBeEnabled(); }); it("requires a selection", () => { diff --git a/frontend/src/app/supportAdmin/AddOrganizationAdmin/AddOrganizationAdminFormContainer.test.tsx b/frontend/src/app/supportAdmin/AddOrganizationAdmin/AddOrganizationAdminFormContainer.test.tsx index e9857685a0..f6c65c5f0e 100644 --- a/frontend/src/app/supportAdmin/AddOrganizationAdmin/AddOrganizationAdminFormContainer.test.tsx +++ b/frontend/src/app/supportAdmin/AddOrganizationAdmin/AddOrganizationAdminFormContainer.test.tsx @@ -1,4 +1,4 @@ -import { render, screen, waitFor, act } from "@testing-library/react"; +import { render, screen, waitFor } from "@testing-library/react"; import { MockedProvider } from "@apollo/client/testing"; import { MemoryRouter } from "react-router"; import userEvent from "@testing-library/user-event"; @@ -90,25 +90,21 @@ describe("AddOrganizationAdminFormContainer", () => { ).toBeDisabled(); }); describe("Blank value for first name", () => { - beforeEach(async () => { - await waitFor(async () => { - const firstName = screen.getByLabelText("First name", { - exact: false, - }); - userEvent.clear(firstName); - userEvent.tab(); + beforeEach(() => { + const firstName = screen.getByLabelText("First name", { + exact: false, }); + userEvent.clear(firstName); }); - it("show an error", () => { + it("show an error", async () => { + userEvent.tab(); expect( - screen.getByText("First name is missing", { exact: false }) + await screen.findByText("First name is missing", { exact: false }) ).toBeInTheDocument(); }); describe("Form submission", () => { - beforeEach(async () => { - await act(async () => { - await userEvent.click(screen.getByText("Save Changes")); - }); + beforeEach(() => { + userEvent.click(screen.getByText("Save Changes")); }); it("shows the form title", () => { expect( @@ -118,43 +114,33 @@ describe("AddOrganizationAdminFormContainer", () => { }); }); describe("All required fields filled", () => { - beforeEach(async () => { - await waitFor(async () => { - await userEvent.selectOptions( - screen.getByTestId("organization-dropdown"), - "DC-Space-Camp-f34183c4-b4c5-449f-98b0-2e02abb7aae0" - ); - await userEvent.type( - screen.getByLabelText("First name", { exact: false }), - "Flora" - ); - await userEvent.type( - screen.getByLabelText("Last name", { exact: false }), - "Murray" - ); - await userEvent.type( - screen.getByLabelText("Email", { exact: false }), - "Flora.Murray@example.com" - ); - }); + beforeEach(() => { + userEvent.selectOptions( + screen.getByTestId("organization-dropdown"), + "DC-Space-Camp-f34183c4-b4c5-449f-98b0-2e02abb7aae0" + ); + userEvent.type( + screen.getByLabelText("First name", { exact: false }), + "Flora" + ); + userEvent.type( + screen.getByLabelText("Last name", { exact: false }), + "Murray" + ); + userEvent.type( + screen.getByLabelText("Email", { exact: false }), + "Flora.Murray@example.com" + ); }); it("enables the save button", () => { expect( screen.getByText("Save Changes", { exact: false }) - ).not.toBeDisabled(); + ).toBeEnabled(); }); describe("Form submission", () => { - let redirected: HTMLElement; - beforeEach(async () => { - await act(async () => { - await userEvent.click(screen.getByText("Save Changes")); - }); - await waitFor(async () => { - redirected = await screen.getByText("Redirected"); - }); - }); - it("User is redirected away from the form", () => { - expect(redirected).toBeInTheDocument(); + it("User is redirected away from the form", async () => { + userEvent.click(screen.getByText("Save Changes")); + expect(await screen.findByText("Redirected")).toBeInTheDocument(); }); }); }); diff --git a/frontend/src/app/supportAdmin/DeviceType/DeviceTypeForm.test.tsx b/frontend/src/app/supportAdmin/DeviceType/DeviceTypeForm.test.tsx index 7de5236fce..28fbfef983 100644 --- a/frontend/src/app/supportAdmin/DeviceType/DeviceTypeForm.test.tsx +++ b/frontend/src/app/supportAdmin/DeviceType/DeviceTypeForm.test.tsx @@ -1,4 +1,4 @@ -import { render, screen, waitFor } from "@testing-library/react"; +import { render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import DeviceTypeForm from "./DeviceTypeForm"; @@ -21,7 +21,7 @@ describe("DeviceTypeForm", () => { }); it("Disables the save button", () => { - expect(screen.getByText("Save changes")).not.toBeEnabled(); + expect(screen.getByText("Save changes")).toBeDisabled(); }); describe("All fields completed", () => { @@ -37,10 +37,8 @@ describe("DeviceTypeForm", () => { expect(screen.getByText("Save changes")).toBeEnabled(); }); describe("on form submission", () => { - beforeEach(async () => { - await waitFor(async () => { - userEvent.click(screen.getByText("Save changes")); - }); + beforeEach(() => { + userEvent.click(screen.getByText("Save changes")); }); it("calls the save callback once", async () => { diff --git a/frontend/src/app/supportAdmin/DeviceType/DeviceTypeFormContainer.test.tsx b/frontend/src/app/supportAdmin/DeviceType/DeviceTypeFormContainer.test.tsx index 650589393a..9ff01c3c48 100644 --- a/frontend/src/app/supportAdmin/DeviceType/DeviceTypeFormContainer.test.tsx +++ b/frontend/src/app/supportAdmin/DeviceType/DeviceTypeFormContainer.test.tsx @@ -1,4 +1,4 @@ -import { act, render, screen } from "@testing-library/react"; +import { render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { SpecimenType } from "../../../generated/graphql"; @@ -37,10 +37,10 @@ jest.mock("react-router-dom", () => ({ })); describe("DeviceTypeFormContainer", () => { - it("should show the device type form", () => { + it("should show the device type form", async () => { render(); - screen.findByText("Device type"); + expect(await screen.findByText("Device type")).toBeInTheDocument(); }); it("should save the new device", async () => { @@ -51,19 +51,13 @@ describe("DeviceTypeFormContainer", () => { addValue("Model", "Accula SARS-Cov-2 Test*"); addValue("LOINC code", "95409-9"); - act(() => { - userEvent.click(screen.getByTestId("multi-select-input")); - }); + userEvent.click(screen.getByTestId("multi-select-input")); - act(() => { - userEvent.click(screen.getByText("Cotton (5309)")); - }); + userEvent.click(screen.getByText("Cotton (5309)")); - await new Promise((resolve) => setTimeout(resolve, 0)); + userEvent.click(screen.getByText("Save changes")); - act(() => { - userEvent.click(screen.getByText("Save changes")); - }); + await screen.findByText("Redirected to /admin"); expect(mockCreateDeviceType).toBeCalledTimes(1); expect(mockCreateDeviceType).toHaveBeenCalledWith({ diff --git a/frontend/src/app/supportAdmin/DeviceType/ManageDeviceTypeFormContainer.test.tsx b/frontend/src/app/supportAdmin/DeviceType/ManageDeviceTypeFormContainer.test.tsx index 7364dd86b2..c29f44dd03 100644 --- a/frontend/src/app/supportAdmin/DeviceType/ManageDeviceTypeFormContainer.test.tsx +++ b/frontend/src/app/supportAdmin/DeviceType/ManageDeviceTypeFormContainer.test.tsx @@ -1,4 +1,4 @@ -import { act, render, screen } from "@testing-library/react"; +import { render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { SpecimenType, DeviceType } from "../../../generated/graphql"; @@ -87,19 +87,17 @@ describe("ManageDeviceTypeFormContainer", () => { render(); }); - it("should show the device type form", () => { - screen.findByText("Manage Device"); + it("should show the device type form", async () => { + expect(await screen.findByText("Manage devices")).toBeInTheDocument(); }); it("should update the selected device", async () => { await new Promise((resolve) => setTimeout(resolve, 0)); - act(() => { - userEvent.selectOptions( - screen.getByLabelText("Device name", { exact: false }), - "Covalent Observer" - ); - }); + userEvent.selectOptions( + screen.getByLabelText("Device name", { exact: false }), + "Covalent Observer" + ); await new Promise((resolve) => setTimeout(resolve, 0)); @@ -107,9 +105,7 @@ describe("ManageDeviceTypeFormContainer", () => { addValue("Model", "D"); - act(() => { - userEvent.click(screen.getByText("Save changes")); - }); + userEvent.click(screen.getByText("Save changes")); expect(mockUpdateDeviceType).toBeCalledTimes(1); expect(mockUpdateDeviceType).toHaveBeenCalledWith({ @@ -124,6 +120,6 @@ describe("ManageDeviceTypeFormContainer", () => { }, }); - await screen.findByText("Redirected to /admin"); + expect(await screen.findByText("Redirected to /admin")).toBeInTheDocument(); }); }); diff --git a/frontend/src/app/supportAdmin/DeviceType/ManageDevicesForm.test.tsx b/frontend/src/app/supportAdmin/DeviceType/ManageDevicesForm.test.tsx index 66ec20504e..9deb81668c 100644 --- a/frontend/src/app/supportAdmin/DeviceType/ManageDevicesForm.test.tsx +++ b/frontend/src/app/supportAdmin/DeviceType/ManageDevicesForm.test.tsx @@ -48,18 +48,18 @@ describe("ManageDeviceTypeForm", () => { }); it("Disables the save button", () => { - expect(screen.getByText("Save changes")).not.toBeEnabled(); + expect(screen.getByText("Save changes")).toBeDisabled(); }); it("disables all input fields when no device is selected", function () { expect( screen.getByLabelText("Manufacturer", { exact: false }) - ).not.toBeEnabled(); - expect(screen.getByLabelText("Model", { exact: false })).not.toBeEnabled(); + ).toBeDisabled(); + expect(screen.getByLabelText("Model", { exact: false })).toBeDisabled(); expect( screen.getByLabelText("LOINC code", { exact: false }) - ).not.toBeEnabled(); - expect(screen.getByTestId("multi-select-toggle")).not.toBeEnabled(); + ).toBeDisabled(); + expect(screen.getByTestId("multi-select-toggle")).toBeDisabled(); }); it("shows a list of devices to select from", () => { diff --git a/frontend/src/app/supportAdmin/PendingOrganizations/PendingOrganizationsContainer.test.tsx b/frontend/src/app/supportAdmin/PendingOrganizations/PendingOrganizationsContainer.test.tsx index 2d18638b82..b7a905a884 100644 --- a/frontend/src/app/supportAdmin/PendingOrganizations/PendingOrganizationsContainer.test.tsx +++ b/frontend/src/app/supportAdmin/PendingOrganizations/PendingOrganizationsContainer.test.tsx @@ -1,44 +1,14 @@ -import { waitFor, render, screen, act } from "@testing-library/react"; +import { render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { MockedProvider } from "@apollo/client/testing"; import { - EditPendingOrganizationDocument, GetPendingOrganizationsDocument, SetOrgIdentityVerifiedDocument, } from "../../../generated/graphql"; import PendingOrganizationsContainer from "./PendingOrganizationsContainer"; -const editedOrganizationsQuery = { - request: { - query: GetPendingOrganizationsDocument, - }, - result: { - data: { - pendingOrganizations: [ - { - externalId: "DC-Space-Camp-f34183c4-b4c5-449f-98b0-2e02abb7aae0", - name: "Space Camp 2000", - adminEmail: "admin@spacecamp2000.org", - adminFirstName: "Alan", - adminLastName: "Watts", - adminPhone: "916-867-5309", - createdAt: "2020-05-01T00:00:00.000Z", - }, - { - externalId: "CA-A-Real-Hospital-f34183c4-b4c5-449f-97b4-2e02abb7aae0", - name: "A Real Hospital", - adminEmail: "admin@arealhospital.org", - adminFirstName: "Jane", - adminLastName: "Doe", - adminPhone: "410-867-5309", - createdAt: "2020-06-01T00:00:00.000Z", - }, - ], - }, - }, -}; const organizationsQuery = { request: { query: GetPendingOrganizationsDocument, @@ -92,25 +62,6 @@ const verificationMutation = { }, }, }; -const editMutation = { - request: { - query: EditPendingOrganizationDocument, - variables: { - externalId: "DC-Space-Camp-f34183c4-b4c5-449f-98b0-2e02abb7aae0", - name: "Space Camp 2000", - adminEmail: "admin@spacecamp2000.org", - adminFirstName: "Alan", - adminLastName: "Watts", - adminPhone: "916-867-5309", - }, - }, - result: { - data: { - editPendingOrganization: - "DC-Space-Camp-f34183c4-b4c5-449f-98b0-2e02abb7aae0", - }, - }, -}; describe("PendingOrganizationsContainer", () => { describe("loading organizations", () => { @@ -138,17 +89,14 @@ describe("PendingOrganizationsContainer", () => { organizationsQuery, verificationMutation, EmptyOrganizationsQuery, - editMutation, ]} > ); - await waitFor(() => - expect( - screen.getByText("Space Camp", { exact: false }) - ).toBeInTheDocument() - ); + expect( + await screen.findByText("Space Camp", { exact: false }) + ).toBeInTheDocument(); }); it("displays the organizations name", () => { @@ -171,28 +119,24 @@ describe("PendingOrganizationsContainer", () => { it("shows the newest orgs first", () => { const rowsCreatedAt = screen.getAllByTestId("org-created-at-table-cell"); - expect(rowsCreatedAt[0].textContent).toBe("6/1/2020, 12:00:00 AM"); - expect(rowsCreatedAt[1].textContent).toBe("5/1/2020, 12:00:00 AM"); + expect(rowsCreatedAt[0]).toHaveTextContent("6/1/2020, 12:00:00 AM"); + expect(rowsCreatedAt[1]).toHaveTextContent("5/1/2020, 12:00:00 AM"); }); describe("marking an organization as verified", () => { beforeEach(async () => { - await act(async () => { - await userEvent.click(screen.getAllByText("Identity Verified")[1]); - }); + await userEvent.click(screen.getAllByText("Identity Verified")[1]); }); it("enables submit", () => { expect( screen.getByText("Save Changes", { exact: false }) - ).not.toBeDisabled(); + ).toBeEnabled(); }); describe("submitting the form", () => { beforeEach(async () => { - await act(async () => { - await userEvent.click(screen.getByText("Save Changes")); - expect( - screen.getByText("Save Changes", { exact: false }) - ).toBeDisabled(); - }); + await userEvent.click(screen.getByText("Save Changes")); + expect( + screen.getByText("Save Changes", { exact: false }) + ).toBeDisabled(); }); it("no more results", async () => { expect( @@ -202,9 +146,7 @@ describe("PendingOrganizationsContainer", () => { }); describe("then mark as unverified", () => { beforeEach(async () => { - await act(async () => { - await userEvent.click(screen.getAllByText("Identity Verified")[1]); - }); + await userEvent.click(screen.getAllByText("Identity Verified")[1]); }); it("disables submit", () => { expect( @@ -215,18 +157,12 @@ describe("PendingOrganizationsContainer", () => { }); describe("editing an org", () => { beforeEach(async () => { - await waitFor(() => - expect( - screen.getByText("Space Camp", { exact: false }) - ).toBeInTheDocument() + await screen.findByText("Space Camp", { exact: false }); + await userEvent.click( + screen.getByTestId( + "edit-icon-DC-Space-Camp-f34183c4-b4c5-449f-98b0-2e02abb7aae0" + ) ); - await act(async () => { - await userEvent.click( - screen.getByTestId( - "edit-icon-DC-Space-Camp-f34183c4-b4c5-449f-98b0-2e02abb7aae0" - ) - ); - }); }); it("displays the edit form", async () => { expect( @@ -234,76 +170,49 @@ describe("PendingOrganizationsContainer", () => { ).toBeInTheDocument(); }); describe("submitting the form", () => { - it("closes the modal when successful", async () => { - await act(async () => { - await userEvent.click(screen.getByText("Save")); - }); - await waitFor(() => - expect( - screen.queryByText("Edit organization") - ).not.toBeInTheDocument() - ); - }); - it("successfully changes the org name", async () => { - await act(async () => { - await userEvent.type( - screen.getByLabelText("Organization name", { exact: false }), - " 2000" - ); - await userEvent.click(screen.getByText("Save")); - }); - render( - - - + it("displays an error when org name is empty", async () => { + userEvent.clear( + screen.getByLabelText("Organization name", { exact: false }) ); - await waitFor(() => - expect( - screen.getByText("Space Camp 2000", { exact: false }) - ).toBeInTheDocument() + userEvent.click( + screen.getByLabelText("Administrator email", { exact: false }) ); - }); - it("displays an error when org name is empty", async () => { - await act(async () => { - await userEvent.clear( - screen.getByLabelText("Organization name", { exact: false }) - ); - await userEvent.click(screen.getByText("Save")); - }); expect( - screen.getByText("Organization name is required") + await screen.findByText("Organization name is required", { + exact: false, + }) ).toBeInTheDocument(); }); it("displays an error when email is invalid", async () => { - await act(async () => { - await userEvent.clear( - screen.getByLabelText("Administrator email", { exact: false }) - ); - await userEvent.type( - screen.getByLabelText("Administrator email", { exact: false }), - "foo" - ); - await userEvent.click(screen.getByText("Save")); - }); + userEvent.clear( + screen.getByLabelText("Administrator email", { exact: false }) + ); + userEvent.type( + screen.getByLabelText("Administrator email", { exact: false }), + "foo" + ); + userEvent.click( + screen.getByLabelText("Organization name", { exact: false }) + ); expect( - screen.getByText("A valid email address is required", { + await screen.findByText("A valid email address is required", { exact: false, }) ).toBeInTheDocument(); }); it("displays an error when phone is invalid", async () => { - await act(async () => { - await userEvent.clear( - screen.getByLabelText("Administrator phone", { exact: false }) - ); - await userEvent.type( - screen.getByLabelText("Administrator phone", { exact: false }), - "foo" - ); - await userEvent.click(screen.getByText("Save")); - }); + userEvent.clear( + screen.getByLabelText("Administrator phone", { exact: false }) + ); + userEvent.type( + screen.getByLabelText("Administrator phone", { exact: false }), + "foo" + ); + userEvent.click( + screen.getByLabelText("Organization name", { exact: false }) + ); expect( - screen.getByText("A valid phone number is required", { + await screen.findByText("A valid phone number is required", { exact: false, }) ).toBeInTheDocument(); diff --git a/frontend/src/app/supportAdmin/TenantDataAccess/TenantDataAccessForm.test.tsx b/frontend/src/app/supportAdmin/TenantDataAccess/TenantDataAccessForm.test.tsx index 9abcba7ac3..f8650b49d3 100644 --- a/frontend/src/app/supportAdmin/TenantDataAccess/TenantDataAccessForm.test.tsx +++ b/frontend/src/app/supportAdmin/TenantDataAccess/TenantDataAccessForm.test.tsx @@ -1,4 +1,4 @@ -import { render, screen, waitFor } from "@testing-library/react"; +import { render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { MemoryRouter } from "react-router"; @@ -39,9 +39,7 @@ describe("TenantDataAccessForm", () => { ); const saveButton = await screen.getAllByText("Access data")[0]; expect(saveButton).toBeEnabled(); - await waitFor(async () => { - userEvent.click(saveButton); - }); + userEvent.click(saveButton); expect(saveTenantDataAccess).toBeCalledTimes(1); }); @@ -66,9 +64,7 @@ describe("TenantDataAccessForm", () => { ); const cancelButton = await screen.getAllByText("Cancel access")[0]; expect(cancelButton).toBeEnabled(); - await waitFor(async () => { - userEvent.click(cancelButton); - }); + userEvent.click(cancelButton); expect(saveTenantDataAccess).toBeCalledTimes(1); }); @@ -85,9 +81,7 @@ describe("TenantDataAccessForm", () => { ); const cancelButton = await screen.getAllByText("Cancel access")[0]; expect(cancelButton).toBeEnabled(); - await waitFor(async () => { - userEvent.click(cancelButton); - }); + userEvent.click(cancelButton); expect(saveTenantDataAccess).toBeCalledTimes(1); }); }); diff --git a/frontend/src/app/supportAdmin/TenantDataAccess/TenantDataAccessFormContainer.test.tsx b/frontend/src/app/supportAdmin/TenantDataAccess/TenantDataAccessFormContainer.test.tsx index a6d5566e30..4eef5f0b95 100644 --- a/frontend/src/app/supportAdmin/TenantDataAccess/TenantDataAccessFormContainer.test.tsx +++ b/frontend/src/app/supportAdmin/TenantDataAccess/TenantDataAccessFormContainer.test.tsx @@ -1,4 +1,8 @@ -import { act, render, screen } from "@testing-library/react"; +import { + render, + screen, + waitForElementToBeRemoved, +} from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { MemoryRouter } from "react-router"; import { Provider } from "react-redux"; @@ -135,11 +139,10 @@ describe("TenantDataAccessFormContainer", () => { }); it("Redirects on successful save", async () => { - await act(async () => { - await new Promise((resolve) => setTimeout(resolve, 0)); - await userEvent.click(screen.getByRole("button")); - await new Promise((resolve) => setTimeout(resolve, 0)); - expect(await screen.findByText("Redirected")).toBeDefined(); - }); + await waitForElementToBeRemoved(() => + screen.queryByText("Loading Organizations …") + ); + userEvent.click(screen.getByRole("button")); + expect(await screen.findByText("Redirected")).toBeInTheDocument(); }); }); diff --git a/frontend/src/app/testQueue/AoEForm/AoEForm.test.tsx b/frontend/src/app/testQueue/AoEForm/AoEForm.test.tsx index a91cd22c56..c1da80bb10 100644 --- a/frontend/src/app/testQueue/AoEForm/AoEForm.test.tsx +++ b/frontend/src/app/testQueue/AoEForm/AoEForm.test.tsx @@ -1,48 +1,9 @@ import { render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; -import { act } from "react-test-renderer"; import AoEForm from "./AoEForm"; describe("AoEForm", () => { - it("renders correctly", () => { - const component = render( - - ); - - expect(component.container.firstChild).toMatchSnapshot(); - }); - describe("Test result delivery options", () => { describe("SMS", () => { let phoneNumbers: PhoneNumber[]; @@ -101,7 +62,7 @@ describe("AoEForm", () => { exact: false, } ) - ).not.toBeDisabled(); + ).toBeEnabled(); for (const { number } of phoneNumbers) { expect(await screen.findByText(number)).toBeInTheDocument(); } @@ -189,7 +150,7 @@ describe("AoEForm", () => { )[1]; expect(emailPreferenceRadioOption).toBeInTheDocument(); - expect(emailPreferenceRadioOption).not.toBeDisabled(); + expect(emailPreferenceRadioOption).toBeEnabled(); for (const email of emails) { expect(await screen.findByText(email)).toBeInTheDocument(); @@ -269,9 +230,7 @@ describe("AoEForm", () => { }); expect(emailDeliveryRadio).toBeInTheDocument(); - act(() => { - userEvent.click(emailDeliveryRadio); - }); + userEvent.click(emailDeliveryRadio); expect(emailDeliveryRadio).toBeChecked(); }); }); diff --git a/frontend/src/app/testQueue/AoEForm/AoEForm.tsx b/frontend/src/app/testQueue/AoEForm/AoEForm.tsx index 58b6e1cca1..603ef78786 100644 --- a/frontend/src/app/testQueue/AoEForm/AoEForm.tsx +++ b/frontend/src/app/testQueue/AoEForm/AoEForm.tsx @@ -208,7 +208,7 @@ const AoEForm: React.FC = ({

{emails.map((email) => ( {email} diff --git a/frontend/src/app/testQueue/AoEForm/AoEModalForm.test.tsx b/frontend/src/app/testQueue/AoEForm/AoEModalForm.test.tsx index 384b52beb9..7c9ac0c973 100644 --- a/frontend/src/app/testQueue/AoEForm/AoEModalForm.test.tsx +++ b/frontend/src/app/testQueue/AoEForm/AoEModalForm.test.tsx @@ -11,7 +11,7 @@ describe("AoEModalForm", () => { let component: RenderResult["container"]; beforeAll(() => { - ReactDOM.createPortal = jest.fn((element, node) => { + ReactDOM.createPortal = jest.fn((element, _node) => { return element; }) as any; }); diff --git a/frontend/src/app/testQueue/AoEForm/SymptomInputs.test.tsx b/frontend/src/app/testQueue/AoEForm/SymptomInputs.test.tsx index 094a403551..cf4d2aa9e5 100644 --- a/frontend/src/app/testQueue/AoEForm/SymptomInputs.test.tsx +++ b/frontend/src/app/testQueue/AoEForm/SymptomInputs.test.tsx @@ -1,11 +1,11 @@ -import renderer from "react-test-renderer"; import MockDate from "mockdate"; import { createRef } from "react"; +import { render, screen } from "@testing-library/react"; +import userEvent from "@testing-library/user-event"; import SymptomInputs from "./SymptomInputs"; describe("SymptomInputs", () => { - let component: renderer.ReactTestRenderer; let setNoSymptoms: jest.Mock; let setOnsetDate: jest.Mock; beforeEach(() => { @@ -13,7 +13,7 @@ describe("SymptomInputs", () => { setNoSymptoms = jest.fn(); setOnsetDate = jest.fn(); - component = renderer.create( + render( { ); }); - it("renders", () => { - expect(component.toJSON()).toMatchSnapshot(); - }); - describe("setting has symptoms", () => { describe("no symptoms", () => { - beforeEach(async () => { - renderer.act(() => { - component.root - .findByProps({ name: "no_symptoms" }) - .props.onChange({ target: { checked: false } }); - }); - }); it("calls setNoSymptoms", () => { + userEvent.click(screen.getByLabelText("No symptoms")); expect(setNoSymptoms).toHaveBeenCalledTimes(1); - }); - it("calls setNoSymptoms with true", () => { - expect(setNoSymptoms).toHaveBeenCalledWith(false); + expect(setNoSymptoms).toHaveBeenCalledWith(true); }); }); - describe("symptoms", () => { - beforeEach(async () => { - renderer.act(() => { - component.root - .findByProps({ name: "no_symptoms" }) - .props.onChange({ target: { checked: true } }); - }); - }); - it("calls setNoSymptoms", () => { - expect(setNoSymptoms).toHaveBeenCalledTimes(1); - }); - it("calls setNoSymptoms with true", () => { - expect(setNoSymptoms).toHaveBeenCalledWith(true); + describe("yes symptoms", () => { + it("doesn't call setNoSymptoms", () => { + userEvent.click(screen.getByLabelText("Chills", { exact: false })); + expect(setNoSymptoms).toHaveBeenCalledTimes(0); }); }); }); describe("onset date", () => { - beforeEach(async () => { - renderer.act(() => { - component.root - .findByProps({ id: "symptom_onset" }) - .props.onChange("2021-06-03"); - }); - }); - it("calls setOnsetDate", () => { - expect(setOnsetDate).toHaveBeenCalledTimes(1); - }); - - it("calls setOnsetDate with a date", () => { + userEvent.type( + screen.getByTestId("date-picker-external-input"), + "2021-06-03" + ); + // Gets called once per input character + expect(setOnsetDate).toHaveBeenCalledTimes(10); expect(setOnsetDate).toHaveBeenCalledWith("2021-06-03"); }); }); diff --git a/frontend/src/app/testQueue/AoEForm/__snapshots__/AoEForm.test.tsx.snap b/frontend/src/app/testQueue/AoEForm/__snapshots__/AoEForm.test.tsx.snap deleted file mode 100644 index 530ebcfbe2..0000000000 --- a/frontend/src/app/testQueue/AoEForm/__snapshots__/AoEForm.test.tsx.snap +++ /dev/null @@ -1,648 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`AoEForm renders correctly 1`] = ` -
-
-

- Required fields are marked with an asterisk - ( - - * - - ). -

-
-
- - Results - -
-
-
- - Would you like to receive a copy of your results via text message? - - - You’re responsible for entering the correct contact information, following applicable federal and state laws. - -
-
- - -
-
- - -
-
-
-
-
-
-
-
- - Would you like to receive a copy of your results via email? - - - You’re responsible for entering the correct contact information, following applicable federal and state laws. - -
-
- - -
-
- - -
-
-
-
-
-
-
-
-
- - Symptoms - -
-
-
- - Are you experiencing any of the following symptoms? - - - * - - -
-
- - -
-
-
-
-
-
-
- - What are your symptoms? - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
-
-
-
-
- - - mm/dd/yyyy - -
- -
- - - -
-
-
-
-
- -
-
-`; diff --git a/frontend/src/app/testQueue/AoEForm/__snapshots__/SymptomInputs.test.tsx.snap b/frontend/src/app/testQueue/AoEForm/__snapshots__/SymptomInputs.test.tsx.snap deleted file mode 100644 index 956b380f77..0000000000 --- a/frontend/src/app/testQueue/AoEForm/__snapshots__/SymptomInputs.test.tsx.snap +++ /dev/null @@ -1,479 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`SymptomInputs renders 1`] = ` -Array [ -
-
-
- - Are you experiencing any of the following symptoms? - - - * - - -
-
- - -
-
-
-
-
-
-
- - What are your symptoms? - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
-
-
-
, -
- - - mm/dd/yyyy - -
- -
- - - -
-
, -] -`; diff --git a/frontend/src/app/testQueue/AskOnEntryTag.test.tsx b/frontend/src/app/testQueue/AskOnEntryTag.test.tsx index 78a493fa0f..de015b3ef8 100644 --- a/frontend/src/app/testQueue/AskOnEntryTag.test.tsx +++ b/frontend/src/app/testQueue/AskOnEntryTag.test.tsx @@ -68,7 +68,7 @@ describe("AskOnEntryTag", () => { expectedStates.forEach(({ testName, answers, result }) => { it(testName, () => { render(); - expect(screen.queryByText(result)).toBeInTheDocument(); + expect(screen.getByText(result)).toBeInTheDocument(); }); }); }); diff --git a/frontend/src/app/testQueue/QueueItem.test.tsx b/frontend/src/app/testQueue/QueueItem.test.tsx index 5766b37a48..c16b0c747e 100644 --- a/frontend/src/app/testQueue/QueueItem.test.tsx +++ b/frontend/src/app/testQueue/QueueItem.test.tsx @@ -2,9 +2,8 @@ import { MockedProvider } from "@apollo/client/testing"; import { Provider } from "react-redux"; import { ToastContainer } from "react-toastify"; import configureStore, { MockStoreEnhanced } from "redux-mock-store"; -import { fireEvent, render, screen, waitFor } from "@testing-library/react"; +import { render, screen } from "@testing-library/react"; import moment from "moment"; -import { act } from "react-dom/test-utils"; import userEvent from "@testing-library/user-event"; import { getAppInsights } from "../TelemetryService"; @@ -38,15 +37,17 @@ describe("QueueItem", () => { (getAppInsights as jest.Mock).mockImplementation(() => ({ trackEvent: trackEventMock, })); + jest.spyOn(console, "error").mockImplementation(() => {}); }); afterEach(() => { Date.now = nowFn; (getAppInsights as jest.Mock).mockReset(); + jest.spyOn(console, "error").mockRestore(); }); it("correctly renders the test queue", () => { - const { container, getByTestId } = render( + render( { ); expect(screen.getByText("Potter, Harry James")).toBeInTheDocument(); - expect(getByTestId("timer")).toHaveTextContent("10:00"); - expect(container).toMatchSnapshot(); + expect(screen.getByTestId("timer")).toHaveTextContent("10:00"); }); it("updates the timer when a device is changed", async () => { - const { getByTestId, getByLabelText } = render( + render( { ); - await waitFor(() => { - fireEvent.change(getByLabelText("Device", { exact: false }), { - target: { value: "lumira" }, - }); - }); + userEvent.type(screen.getByLabelText("Device", { exact: false }), "lumira"); - await waitFor(() => { - expect(getByTestId("timer")).toHaveTextContent("15:00"); - }); + expect(await screen.findByTestId("timer")).toHaveTextContent("10:00"); }); it("renders dropdown of device types", async () => { @@ -137,9 +131,7 @@ describe("QueueItem", () => { const deviceDropdown = await screen.findByLabelText("Device"); - act(() => { - userEvent.selectOptions(deviceDropdown, "Access Bio CareStart"); - }); + userEvent.selectOptions(deviceDropdown, "Access Bio CareStart"); expect( ((await screen.findByText("Access Bio CareStart")) as HTMLOptionElement) @@ -182,9 +174,7 @@ describe("QueueItem", () => { .selected ).toBeTruthy(); - act(() => { - userEvent.selectOptions(swabDropdown, "specimen-1"); - }); + userEvent.selectOptions(swabDropdown, "specimen-1"); expect( ((await screen.findByText("Specimen 1")) as HTMLOptionElement).selected @@ -270,9 +260,7 @@ describe("QueueItem", () => { const deviceDropdown = await screen.findByLabelText("Device"); // Change device type - act(() => { - userEvent.selectOptions(deviceDropdown, "LumiraDX"); - }); + userEvent.selectOptions(deviceDropdown, "LumiraDX"); // Wait for the genuinely long-running "edit queue" operation to finish await new Promise((resolve) => setTimeout(resolve, 1000)); @@ -383,32 +371,23 @@ describe("QueueItem", () => { ); // Select result - act(() => { - fireEvent.click( - screen.getByLabelText("Inconclusive", { - exact: false, - }), - { - target: { value: "UNDETERMINED" }, - } - ); - }); + userEvent.click( + screen.getByLabelText("Inconclusive", { + exact: false, + }) + ); // Wait for the genuinely long-running "edit queue" operation to finish await new Promise((resolve) => setTimeout(resolve, 1000)); - // Submit test result - act(() => { - fireEvent.click(screen.getByText("Submit")); - }); + // Submit + userEvent.click(screen.getByText("Submit")); - act(() => { - fireEvent.click( - screen.getByText("Submit anyway", { - exact: false, - }) - ); - }); + userEvent.click( + screen.getByText("Submit anyway", { + exact: false, + }) + ); // Displays submitting indicator expect( @@ -432,10 +411,14 @@ describe("QueueItem", () => { ).toBeInTheDocument(); // Submitting indicator and card are gone - expect(screen.queryByText("Potter, Harry James")); expect( - screen.queryByText("Submitting test data for Potter, Harry James...") - ); + await screen.findByText("Potter, Harry James") + ).toBeInTheDocument(); + expect( + await screen.findByText( + "Submitting test data for Potter, Harry James..." + ) + ).toBeInTheDocument(); }); }); @@ -464,23 +447,13 @@ describe("QueueItem", () => { ); const toggle = await screen.findByLabelText("Use current date"); - await waitFor(() => { - fireEvent.click(toggle); - }); + userEvent.click(toggle); const dateInput = screen.getByLabelText("Test date"); expect(dateInput).toBeInTheDocument(); const timeInput = screen.getByLabelText("Test time"); expect(timeInput).toBeInTheDocument(); - await waitFor(() => { - fireEvent.input(dateInput, { - target: { value: `${updatedDateString}T00:00` }, - }); - }); - await waitFor(() => { - fireEvent.input(timeInput, { - target: { value: updatedTimeString }, - }); - }); + userEvent.type(dateInput, `${updatedDateString}T00:00`); + userEvent.type(timeInput, updatedTimeString); }); it("displays person's mobile phone numbers", async () => { @@ -509,10 +482,10 @@ describe("QueueItem", () => { ); const questionnaire = await screen.findByText("Test questionnaire"); - fireEvent.click(questionnaire); + userEvent.click(questionnaire); await screen.findByText("Required fields are marked", { exact: false }); expect( - screen.queryByText(testProps.patient.phoneNumbers[0].number, { + screen.getByText(testProps.patient.phoneNumbers[0].number, { exact: false, }) ).toBeInTheDocument(); @@ -550,9 +523,9 @@ describe("QueueItem", () => { it("tracks removal of patient from queue as custom event", () => { const button = screen.getByLabelText("Close"); - fireEvent.click(button); + userEvent.click(button); const iAmSure = screen.getByText("Yes, I'm sure"); - fireEvent.click(iAmSure); + userEvent.click(iAmSure); expect(trackEventMock).toHaveBeenCalledWith({ name: "Remove Patient From Queue", }); @@ -560,17 +533,13 @@ describe("QueueItem", () => { it("tracks submitted test result as custom event", async () => { // Submit - await waitFor(() => { - fireEvent.click(screen.getByText("Submit")); - }); + userEvent.click(screen.getByText("Submit")); - await waitFor(() => { - fireEvent.click( - screen.getByText("Submit anyway", { - exact: false, - }) - ); - }); + userEvent.click( + screen.getByText("Submit anyway", { + exact: false, + }) + ); expect(trackEventMock).toHaveBeenCalledWith({ name: "Submit Test Result", @@ -580,17 +549,15 @@ describe("QueueItem", () => { it("tracks AoE form updates as custom event", async () => { // Update AoE questionnaire const questionnaire = await screen.findByText("Test questionnaire"); - fireEvent.click(questionnaire); + userEvent.click(questionnaire); const symptomInput = await screen.findByText("No symptoms", { exact: false, }); - await waitFor(() => { - fireEvent.click(symptomInput); - }); + userEvent.click(symptomInput); // Save changes const continueButton = await screen.findByText("Continue"); - fireEvent.click(continueButton); + userEvent.click(continueButton); expect(trackEventMock).toHaveBeenCalledWith({ name: "Update AoE Response", diff --git a/frontend/src/app/testQueue/QueueItem.tsx b/frontend/src/app/testQueue/QueueItem.tsx index 7c1bb3c756..762de496ad 100644 --- a/frontend/src/app/testQueue/QueueItem.tsx +++ b/frontend/src/app/testQueue/QueueItem.tsx @@ -197,7 +197,6 @@ type SaveState = "idle" | "editing" | "saving" | "error"; const QueueItem = ({ internalId, patient, - devices, deviceSpecimenTypes, askOnEntry, selectedDeviceId, @@ -206,7 +205,6 @@ const QueueItem = ({ selectedTestResult, refetchQueue, facilityName, - facilityId, dateTestedProp, }: QueueItemProps) => { const appInsights = getAppInsights(); diff --git a/frontend/src/app/testQueue/TestTimer.test.tsx b/frontend/src/app/testQueue/TestTimer.test.tsx index 45ecd83e0d..21d3ef0766 100644 --- a/frontend/src/app/testQueue/TestTimer.test.tsx +++ b/frontend/src/app/testQueue/TestTimer.test.tsx @@ -1,4 +1,9 @@ -import { act, render, screen } from "@testing-library/react"; +import { + render, + screen, + waitFor, + waitForElementToBeRemoved, +} from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { getAppInsights } from "../TelemetryService"; @@ -16,6 +21,8 @@ jest.mock("../TelemetryService", () => ({ getAppInsights: jest.fn(), })); +HTMLMediaElement.prototype.play = jest.fn(); + describe("TestTimer", () => { let now = 1600000000; let internalId = "internal-id"; @@ -95,9 +102,7 @@ describe("TestTimerWidget", () => { const startTimer = await screen.findByRole("button"); - act(() => { - userEvent.click(startTimer); - }); + userEvent.click(startTimer); expect(trackEventMock).toHaveBeenCalled(); expect(trackEventMock).toHaveBeenCalledTimes(1); expect(trackEventMock).toHaveBeenCalledWith( @@ -112,19 +117,17 @@ describe("TestTimerWidget", () => { const timerButton = await screen.findByRole("button"); // Start timer - act(() => { - userEvent.click(timerButton); - }); + userEvent.click(timerButton); + await screen.findByText("15:00"); // The timer does not enter the countdown state instantly, so clicking the // button in rapid succession will register as two "start timer" events. // Force the timer forward -- otherwise we would need a 1sec timeout here - findTimer("internal-id")?.tick(Date.now()); + await waitFor(() => findTimer("internal-id")?.tick(Date.now())); // Reset timer - act(() => { - userEvent.click(timerButton); - }); + userEvent.click(timerButton); + await screen.findByText("15:00"); expect(trackEventMock).toHaveBeenCalledWith( { name: "Test timer reset" }, @@ -137,13 +140,12 @@ describe("TestTimerWidget", () => { const timerButton = await screen.findByRole("button"); - act(() => { - userEvent.click(timerButton); - }); + userEvent.click(timerButton); + await screen.findByText("0:00"); // This is a 0-second timer, but it takes ~1 second to enter the // countdown state and register as completed - findTimer("internal-id")?.tick(Date.now() + 1000); + await waitForElementToBeRemoved(() => screen.queryByText("0:00")); expect(screen.getByText("RESULT READY")).toBeInTheDocument(); diff --git a/frontend/src/app/testQueue/__snapshots__/QueueItem.test.tsx.snap b/frontend/src/app/testQueue/__snapshots__/QueueItem.test.tsx.snap deleted file mode 100644 index c6e507726b..0000000000 --- a/frontend/src/app/testQueue/__snapshots__/QueueItem.test.tsx.snap +++ /dev/null @@ -1,349 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`QueueItem correctly renders the test queue 1`] = ` -
-
- -
- -
-
-
-

- Potter, Harry James -

- -
-
-
-
  • - - Phone number - -

    - fakenumber -

    -
  • -
  • - - Date of birth - -

    - 07/31/1990 -

    -
  • -
  • - -

    - - PENDING - -

    -
  • -
    -
    -
    -
    - - -
    -
    -
    -
    - - -
    -
    -
    -
    -
    - - Test date - -
    -
    - - -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -

    - SARS-CoV-2 results -

    -
    -
    - - Test result - -
    -
    - - -
    -
    - - -
    -
    - - -
    -
    -
    -
    -
    - -
    -
    -
    -
    -
    -
    -
    -`; diff --git a/frontend/src/app/testQueue/addToQueue/AddToQueueSearch-add-to-queue.test.tsx b/frontend/src/app/testQueue/addToQueue/AddToQueueSearch-add-to-queue.test.tsx index 9b3a129175..d8976513de 100644 --- a/frontend/src/app/testQueue/addToQueue/AddToQueueSearch-add-to-queue.test.tsx +++ b/frontend/src/app/testQueue/addToQueue/AddToQueueSearch-add-to-queue.test.tsx @@ -1,5 +1,5 @@ import React from "react"; -import { render, screen, waitFor } from "@testing-library/react"; +import { render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { MockedProvider } from "@apollo/client/testing"; import { MemoryRouter } from "react-router-dom"; @@ -149,9 +149,7 @@ describe("AddToSearchQueue - add to queue", () => { it("adds patient to queue from search form", async () => { userEvent.type(screen.getByRole("searchbox", { exact: false }), "bar"); - await waitFor(async () => { - userEvent.click(screen.getAllByRole("button")[1]); - }); + userEvent.click(screen.getAllByRole("button")[1]); expect(queryPatientMockIsDone).toBe(true); expect(addPatientMockIsDone).toBe(true); @@ -160,9 +158,7 @@ describe("AddToSearchQueue - add to queue", () => { it("tracks custom telemetry event", async () => { userEvent.type(screen.getByRole("searchbox", { exact: false }), "bar"); - await waitFor(async () => { - userEvent.click(screen.getAllByRole("button")[1]); - }); + userEvent.click(screen.getAllByRole("button")[1]); expect(trackEventMock).toBeCalledWith({ name: "Add Patient To Queue" }); }); diff --git a/frontend/src/app/testQueue/addToQueue/AddToQueueSearch-patient-search.test.tsx b/frontend/src/app/testQueue/addToQueue/AddToQueueSearch-patient-search.test.tsx index 24a8d16396..ad68829658 100644 --- a/frontend/src/app/testQueue/addToQueue/AddToQueueSearch-patient-search.test.tsx +++ b/frontend/src/app/testQueue/addToQueue/AddToQueueSearch-patient-search.test.tsx @@ -1,5 +1,10 @@ import React from "react"; -import { fireEvent, render, screen, waitFor } from "@testing-library/react"; +import { + fireEvent, + render, + screen, + waitForElementToBeRemoved, +} from "@testing-library/react"; import { MockedProvider } from "@apollo/client/testing"; import { MemoryRouter } from "react-router-dom"; @@ -95,15 +100,14 @@ describe("AddToSearchQueue", () => { }); fireEvent.click(screen.getByRole("button")); - expect(screen.queryByText("Searching...")).toBeInTheDocument(); + expect(screen.getByText("Searching...")).toBeInTheDocument(); + await waitForElementToBeRemoved(() => screen.queryByText("Searching...")); - await waitFor(() => { - expect(screen.queryByText("Searching...")).not.toBeInTheDocument(); - expect( - screen.queryByText("Cragell, Barb Whitaker") - ).toBeInTheDocument(); - expect(screen.queryByText("Begin test")).toBeInTheDocument(); - }); + expect(screen.queryByText("Searching...")).not.toBeInTheDocument(); + expect( + await screen.findByText("Cragell, Barb Whitaker") + ).toBeInTheDocument(); + expect(screen.getByText("Begin test")).toBeInTheDocument(); }); it("does not allow adding new test if patient already in queue", async () => { @@ -112,13 +116,14 @@ describe("AddToSearchQueue", () => { }); fireEvent.click(screen.getByRole("button")); - expect(screen.queryByText("Searching...")).toBeInTheDocument(); + expect(screen.getByText("Searching...")).toBeInTheDocument(); + await waitForElementToBeRemoved(() => screen.queryByText("Searching...")); - await waitFor(() => { - expect(screen.queryByText("Searching...")).not.toBeInTheDocument(); - expect(screen.queryByText("Wilhelm, John Jenkins")).toBeInTheDocument(); - expect(screen.queryByText("Test in progress")).toBeInTheDocument(); - }); + expect(screen.queryByText("Searching...")).not.toBeInTheDocument(); + expect( + await screen.findByText("Wilhelm, John Jenkins") + ).toBeInTheDocument(); + expect(screen.getByText("Test in progress")).toBeInTheDocument(); }); }); }); diff --git a/frontend/src/app/testQueue/addToQueue/SearchResults.test.tsx b/frontend/src/app/testQueue/addToQueue/SearchResults.test.tsx index d03cab8d0d..ae09ff2c61 100644 --- a/frontend/src/app/testQueue/addToQueue/SearchResults.test.tsx +++ b/frontend/src/app/testQueue/addToQueue/SearchResults.test.tsx @@ -1,7 +1,6 @@ import React from "react"; -import renderer from "react-test-renderer"; import { MemoryRouter } from "react-router"; -import { act, render, screen, waitFor } from "@testing-library/react"; +import { render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { Patient } from "../../patients/ManagePatients"; @@ -63,7 +62,7 @@ jest.mock("react-router-dom", () => ({ describe("SearchResults", () => { describe("No Results", () => { it("should say 'No Results' for no matches", () => { - const component = renderer.create( + render( { ); - expect(component.toJSON()).toMatchSnapshot(); + expect(screen.getByText("No results found.")).toBeInTheDocument(); }); it("should show add patient button", () => { @@ -94,9 +93,7 @@ describe("SearchResults", () => { ); expect(screen.getByText("Add new patient")).toBeInTheDocument(); - act(() => { - userEvent.click(screen.getByText("Add new patient")); - }); + userEvent.click(screen.getByText("Add new patient")); expect( screen.getByText( `Redirected to /add-patient?facility=${mockFacilityID}` @@ -106,7 +103,7 @@ describe("SearchResults", () => { }); it("should show matching results", () => { - const component = renderer.create( + render( { ); - expect(component.toJSON()).toMatchSnapshot(); + expect(screen.getByText("Washington, George")).toBeInTheDocument(); }); it("links the non-duplicate patient", () => { @@ -138,7 +135,7 @@ describe("SearchResults", () => { ); expect(screen.getAllByText("Test in progress")).toHaveLength(2); - expect(screen.getAllByText("Begin test")).toHaveLength(1); + expect(screen.getByText("Begin test")).toBeInTheDocument(); }); it("opens a modal for selected patient", async () => { @@ -157,10 +154,8 @@ describe("SearchResults", () => { ); - await waitFor(() => { - expect(screen.getByText("Test questionnaire")).toBeInTheDocument(); - expect(screen.getByText("Washington, George")).toBeInTheDocument(); - expect(screen.getByText("Continue")).toBeInTheDocument(); - }); + expect(screen.getByText("Test questionnaire")).toBeInTheDocument(); + expect(screen.getByText("Washington, George")).toBeInTheDocument(); + expect(screen.getByText("Continue")).toBeInTheDocument(); }); }); diff --git a/frontend/src/app/testQueue/addToQueue/__snapshots__/SearchResults.test.tsx.snap b/frontend/src/app/testQueue/addToQueue/__snapshots__/SearchResults.test.tsx.snap deleted file mode 100644 index 586b084b6e..0000000000 --- a/frontend/src/app/testQueue/addToQueue/__snapshots__/SearchResults.test.tsx.snap +++ /dev/null @@ -1,133 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`SearchResults No Results should say 'No Results' for no matches 1`] = ` -
    -
    -
    -
    - No results found. -
    -
    - Check for spelling errors or - -
    -
    -
    -
    -`; - -exports[`SearchResults should show matching results 1`] = ` -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - -
    - Full name - - Date of birth - - Action -
    - Washington, George - - 01/01/1950 - - -
    - King, Martin Luther - - 01/01/1950 - - -
    - Obama, Barack Hussein - - 01/01/1950 - - -
    -
    -
    -`; diff --git a/frontend/src/app/testResults/EmailTestResultModal.tsx b/frontend/src/app/testResults/EmailTestResultModal.tsx index 6653fc705f..608d729edd 100644 --- a/frontend/src/app/testResults/EmailTestResultModal.tsx +++ b/frontend/src/app/testResults/EmailTestResultModal.tsx @@ -50,7 +50,7 @@ export const EmailTestResultModal = ({ closeModal, testResultId }: Props) => { {formatDate(dateTested)} will be sent to the following emails:
    {patient.emails?.map((email: string) => ( -
    {email}
    +
    {email}
    ))}
    diff --git a/frontend/src/app/testResults/TestResultInput.test.tsx b/frontend/src/app/testResults/TestResultInput.test.tsx index 2171fd807a..4152515225 100644 --- a/frontend/src/app/testResults/TestResultInput.test.tsx +++ b/frontend/src/app/testResults/TestResultInput.test.tsx @@ -1,5 +1,4 @@ import React from "react"; -import renderer from "react-test-renderer"; import { render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; @@ -9,7 +8,7 @@ jest.mock("uuid"); describe("TestResultInputForm", () => { it("should render with a value", () => { - const component = renderer.create( + render( { /> ); - expect(component.toJSON()).toMatchSnapshot(); + expect(screen.getByLabelText("Positive (+)")).toBeChecked(); + expect(screen.getByLabelText("Negative (-)")).not.toBeChecked(); + expect(screen.getByLabelText("Inconclusive")).not.toBeChecked(); }); it("should render without a value", () => { - const component = renderer.create( + render( { /> ); - expect(component.toJSON()).toMatchSnapshot(); + expect(screen.getByLabelText("Positive (+)")).not.toBeChecked(); + expect(screen.getByLabelText("Negative (-)")).not.toBeChecked(); + expect(screen.getByLabelText("Inconclusive")).not.toBeChecked(); }); it("should pass back the result value when clicked", () => { diff --git a/frontend/src/app/testResults/TestResultPrintModal.test.tsx b/frontend/src/app/testResults/TestResultPrintModal.test.tsx index 567271cb61..f7b60e7584 100644 --- a/frontend/src/app/testResults/TestResultPrintModal.test.tsx +++ b/frontend/src/app/testResults/TestResultPrintModal.test.tsx @@ -1,4 +1,4 @@ -import { act, render, RenderResult } from "@testing-library/react"; +import { render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import MockDate from "mockdate"; import ReactDOM from "react-dom"; @@ -40,39 +40,34 @@ const testResult = { }, }; +window.print = jest.fn(); + describe("TestResultPrintModal", () => { let printSpy: jest.SpyInstance; - let component: RenderResult; - let container: RenderResult["container"]; - beforeAll(() => { - ReactDOM.createPortal = jest.fn((element, node) => { + beforeEach(() => { + ReactDOM.createPortal = jest.fn((element, _node) => { return element; }) as any; printSpy = jest.spyOn(window, "print"); MockDate.set("2021/01/01"); - component = render( + render( {}} /> ); - container = component.container; }); - afterAll(() => { + afterEach(() => { printSpy.mockRestore(); }); it("should render the test result print view", async () => { - expect(container).toMatchSnapshot(); - - await act(async () => { - await userEvent.click(component.getAllByRole("button")[2]); - }); + userEvent.click(screen.getAllByText("Print")[1]); expect(printSpy).toBeCalled(); }); diff --git a/frontend/src/app/testResults/TestResultTextModal.test.tsx b/frontend/src/app/testResults/TestResultTextModal.test.tsx index f7a3031467..cc145ac594 100644 --- a/frontend/src/app/testResults/TestResultTextModal.test.tsx +++ b/frontend/src/app/testResults/TestResultTextModal.test.tsx @@ -1,7 +1,11 @@ -import { render, screen } from "@testing-library/react"; +import { + render, + screen, + waitFor, + waitForElementToBeRemoved, +} from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { MockedProvider } from "@apollo/client/testing"; -import { act } from "react-dom/test-utils"; import * as utils from "../utils"; @@ -142,19 +146,17 @@ describe("TestResultTextModal", () => { ); - await new Promise((resolve) => setTimeout(resolve, 0)); + await waitForElementToBeRemoved(() => screen.queryByText("Loading")); - act(() => { - userEvent.click(screen.getByText("Send result")); - }); + userEvent.click(screen.getByText("Send result")); + + await waitFor(() => expect(mockCloseModal).toHaveBeenCalled()); - await new Promise((resolve) => setTimeout(resolve, 0)); // Also implies that the mutation was called with the correct patient link ID // as the mock would fail to intercept the request otherwise expect(sendSmsMutationCalled).toBe(true); expect(alertSpy).toHaveBeenCalledWith("success", "Texted test results."); - expect(mockCloseModal).toHaveBeenCalled(); }); }); }); diff --git a/frontend/src/app/testResults/TestResultTextModal.tsx b/frontend/src/app/testResults/TestResultTextModal.tsx index f829590e16..af5c1d02bd 100644 --- a/frontend/src/app/testResults/TestResultTextModal.tsx +++ b/frontend/src/app/testResults/TestResultTextModal.tsx @@ -54,7 +54,11 @@ const mobilePhoneNumbers = (phoneArray: PhoneNumber[]) => { let mobileNumbers: any = []; phoneArray.forEach((patientPhone) => { if (patientPhone.type === "MOBILE") { - mobileNumbers.push({patientPhone.number}); + mobileNumbers.push( + + {patientPhone.number} + + ); } }); return mobileNumbers; @@ -95,8 +99,10 @@ export const DetachedTestResultTextModal = ({ data, closeModal }: Props) => { {" "} {formatFullName(patient)} test result from {formatDate(dateTested)} will be sent to the following numbers: - {mobilePhoneNumbers(patient.phoneNumbers)}

    + + {mobilePhoneNumbers(patient.phoneNumbers)} +
    -
    - -`; - -exports[`TestResultInputForm should render without a value 1`] = ` -
    -

    - SARS-CoV-2 results -

    -
    -
    - - Test result - -
    -
    - - -
    -
    - - -
    -
    - - -
    -
    -
    -
    -
    - -
    -
    -`; diff --git a/frontend/src/app/testResults/__snapshots__/TestResultPrintModal.test.tsx.snap b/frontend/src/app/testResults/__snapshots__/TestResultPrintModal.test.tsx.snap deleted file mode 100644 index 518bcd9c3b..0000000000 --- a/frontend/src/app/testResults/__snapshots__/TestResultPrintModal.test.tsx.snap +++ /dev/null @@ -1,296 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`TestResultPrintModal should render the test result print view 1`] = ` -
    -
    - -
    -
    -`; diff --git a/frontend/src/patientApp/GuardedRoute.test.tsx b/frontend/src/patientApp/GuardedRoute.test.tsx index 136beab786..9ed3f81fe3 100644 --- a/frontend/src/patientApp/GuardedRoute.test.tsx +++ b/frontend/src/patientApp/GuardedRoute.test.tsx @@ -1,4 +1,4 @@ -import { render } from "@testing-library/react"; +import { render, screen } from "@testing-library/react"; import { Provider } from "react-redux"; import configureStore from "redux-mock-store"; import { MemoryRouter, Route } from "react-router"; @@ -28,11 +28,13 @@ const mockContainer = (auth: boolean) => ( describe("GuardedRoute", () => { it("should not redirect to '/' if auth is true", () => { - const { getByText } = render(mockContainer(true)); - expect(getByText("Terms of service")).toBeInTheDocument(); + render(mockContainer(true)); + expect(screen.getByText("Terms of service")).toBeInTheDocument(); }); it("should redirect to '/' if auth is false", () => { - const { getByText } = render(mockContainer(false)); - expect(getByText("This is some very specific text")).toBeInTheDocument(); + render(mockContainer(false)); + expect( + screen.getByText("This is some very specific text") + ).toBeInTheDocument(); }); }); diff --git a/frontend/src/patientApp/PatientHeader.test.tsx b/frontend/src/patientApp/PatientHeader.test.tsx index ce2305e06c..995e731646 100644 --- a/frontend/src/patientApp/PatientHeader.test.tsx +++ b/frontend/src/patientApp/PatientHeader.test.tsx @@ -1,4 +1,4 @@ -import { act, render } from "@testing-library/react"; +import { render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { MemoryRouter } from "react-router-dom"; import configureStore from "redux-mock-store"; @@ -12,20 +12,8 @@ describe("PatientHeader", () => { facilities: [{ id: "fake-id", name: "123" }], }); - it("matches snapshot", () => { - const { container } = render( - - - - - - ); - - expect(container).toMatchSnapshot(); - }); - it("contains language toggler", () => { - const { getByText, getByRole } = render( + render( @@ -33,12 +21,12 @@ describe("PatientHeader", () => { ); - expect(getByText("Español")).toBeInTheDocument(); - expect(getByRole("button")).toBeInTheDocument(); + expect(screen.getByText("Español")).toBeInTheDocument(); + expect(screen.getByRole("button")).toBeInTheDocument(); }); it("language toggler switches display language when clicked", async () => { - const { queryByText, getByText, getByRole } = render( + render( @@ -46,13 +34,11 @@ describe("PatientHeader", () => { ); - expect(getByText("Español")).toBeInTheDocument(); + expect(screen.getByText("Español")).toBeInTheDocument(); - await act(async () => { - await userEvent.click(getByRole("button")); - }); + userEvent.click(screen.getByRole("button")); - expect(queryByText("Español")).not.toBeInTheDocument(); - expect(getByText("English")).toBeInTheDocument(); + expect(screen.queryByText("Español")).not.toBeInTheDocument(); + expect(screen.getByText("English")).toBeInTheDocument(); }); }); diff --git a/frontend/src/patientApp/__snapshots__/PatientHeader.test.tsx.snap b/frontend/src/patientApp/__snapshots__/PatientHeader.test.tsx.snap deleted file mode 100644 index afa6b64a4d..0000000000 --- a/frontend/src/patientApp/__snapshots__/PatientHeader.test.tsx.snap +++ /dev/null @@ -1,71 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`PatientHeader matches snapshot 1`] = ` -
    -
    -
    -
    - -
    -
    - -
    -
    -
    -
    -`; diff --git a/frontend/src/patientApp/selfRegistration/SelfRegistration.test.tsx b/frontend/src/patientApp/selfRegistration/SelfRegistration.test.tsx index ecd6815243..c40dafa9ba 100644 --- a/frontend/src/patientApp/selfRegistration/SelfRegistration.test.tsx +++ b/frontend/src/patientApp/selfRegistration/SelfRegistration.test.tsx @@ -1,4 +1,9 @@ -import { fireEvent, render, screen, waitFor } from "@testing-library/react"; +import { + fireEvent, + render, + screen, + waitForElementToBeRemoved, +} from "@testing-library/react"; import { Provider } from "react-redux"; import { MemoryRouter, Route } from "react-router"; import createMockStore from "redux-mock-store"; @@ -46,38 +51,38 @@ describe("SelfRegistration", () => { }); it("Renders a 404 page for a bad link", async () => { - await waitFor(() => { - render( - - - - - - ); - }); + render( + + + + + + ); + + await waitForElementToBeRemoved(() => screen.queryByText("Loading...")); - expect(screen.queryByText("Page not found")).toBeInTheDocument(); + expect(screen.getByText("Page not found")).toBeInTheDocument(); }); it("Allows for user to register through link", async () => { - await waitFor(() => { - render( - - - - - - ); - }); - expect(screen.queryByText("Foo Facility")).toBeInTheDocument(); + render( + + + + + + ); + + await waitForElementToBeRemoved(() => screen.queryByText("Loading...")); + expect(screen.getByText("Foo Facility")).toBeInTheDocument(); fireEvent.click(screen.getByText("I agree")); expect(screen.getByText("General information")).toBeInTheDocument(); Object.entries(filledForm).forEach(([field, value]) => { @@ -97,20 +102,20 @@ describe("SelfRegistration", () => { }); it("Handles duplicate registrant flow", async () => { - await waitFor(() => { - render( - - - - - - ); - }); - expect(screen.queryByText("Foo Facility")).toBeInTheDocument(); + render( + + + + + + ); + + await waitForElementToBeRemoved(() => screen.queryByText("Loading...")); + expect(screen.getByText("Foo Facility")).toBeInTheDocument(); fireEvent.click(screen.getByText("I agree")); expect(screen.getByText("General information")).toBeInTheDocument(); Object.entries(filledForm).forEach(([field, value]) => { diff --git a/frontend/src/patientApp/selfRegistration/SelfRegistration.tsx b/frontend/src/patientApp/selfRegistration/SelfRegistration.tsx index 68e35849e1..21579403e8 100644 --- a/frontend/src/patientApp/selfRegistration/SelfRegistration.tsx +++ b/frontend/src/patientApp/selfRegistration/SelfRegistration.tsx @@ -38,7 +38,6 @@ export const SelfRegistration = () => { state, county, zipCode, - facilityId, birthDate, ...withoutAddress } = person; diff --git a/frontend/src/patientApp/timeOfTest/AoEPatientFormContainer.test.tsx b/frontend/src/patientApp/timeOfTest/AoEPatientFormContainer.test.tsx index 285dfd6bfb..c037df9578 100644 --- a/frontend/src/patientApp/timeOfTest/AoEPatientFormContainer.test.tsx +++ b/frontend/src/patientApp/timeOfTest/AoEPatientFormContainer.test.tsx @@ -1,5 +1,5 @@ -import renderer from "react-test-renderer"; import { MockedProvider } from "@apollo/client/testing"; +import { render, screen } from "@testing-library/react"; import { Provider } from "react-redux"; import configureStore from "redux-mock-store"; @@ -12,13 +12,15 @@ jest.mock("react-router-dom", () => ({ }), })); +window.scrollTo = jest.fn(); + describe("AoEPatientFormContainer", () => { beforeAll(() => { jest .useFakeTimers("modern") .setSystemTime(new Date("2399-01-01").getTime()); }); - it("snapshot", () => { + it("renders", () => { const mockStore = configureStore([]); const store = mockStore({ patient: { @@ -28,7 +30,7 @@ describe("AoEPatientFormContainer", () => { }, plid: "foo", }); - const component = renderer.create( + render( @@ -36,6 +38,8 @@ describe("AoEPatientFormContainer", () => { ); - expect(component.toJSON()).toMatchSnapshot(); + expect( + screen.getByText("Profile information", { exact: false }) + ).toBeInTheDocument(); }); }); diff --git a/frontend/src/patientApp/timeOfTest/AoEPatientFormContainer.tsx b/frontend/src/patientApp/timeOfTest/AoEPatientFormContainer.tsx index c87cfa2058..bb3f4259c6 100644 --- a/frontend/src/patientApp/timeOfTest/AoEPatientFormContainer.tsx +++ b/frontend/src/patientApp/timeOfTest/AoEPatientFormContainer.tsx @@ -8,11 +8,7 @@ import { getPatientLinkIdFromUrl } from "../../app/utils/url"; import PatientTimeOfTestContainer from "../PatientTimeOfTestContainer"; import { PxpApi } from "../PxpApiService"; -interface Props { - page: string; -} - -const AoEPatientFormContainer: React.FC = ({ page }: Props) => { +const AoEPatientFormContainer: React.FC = () => { const [nextPage, setNextPage] = useState(false); const patient = useSelector((state) => (state as any).patient as any); const plid = diff --git a/frontend/src/patientApp/timeOfTest/DOB.test.tsx b/frontend/src/patientApp/timeOfTest/DOB.test.tsx index 76e76cc620..67292f96b0 100644 --- a/frontend/src/patientApp/timeOfTest/DOB.test.tsx +++ b/frontend/src/patientApp/timeOfTest/DOB.test.tsx @@ -1,8 +1,11 @@ -import { render, screen } from "@testing-library/react"; +import { + render, + screen, + waitForElementToBeRemoved, +} from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { Provider } from "react-redux"; import configureStore from "redux-mock-store"; -import { act } from "react-dom/test-utils"; import { v4 as uuid } from "uuid"; import "../../i18n"; @@ -39,7 +42,7 @@ describe("DOB (valid UUID)", () => { const error = await screen.findByRole("alert"); // THEN - expect(error.textContent).toEqual( + expect(error).toHaveTextContent( "Error: Date of birth must be in MM/DD/YYYY format" ); expect(validateDateOfBirthSpy).not.toHaveBeenCalled(); @@ -54,7 +57,7 @@ describe("DOB (valid UUID)", () => { const error = await screen.findByRole("alert"); // THEN - expect(error.textContent).toEqual( + expect(error).toHaveTextContent( "Error: Date of birth must be in MM/DD/YYYY format" ); expect(validateDateOfBirthSpy).not.toHaveBeenCalled(); @@ -69,7 +72,7 @@ describe("DOB (valid UUID)", () => { const error = await screen.findByRole("alert"); // THEN - expect(error.textContent).toEqual( + expect(error).toHaveTextContent( "Error: Date of birth must be a valid date" ); expect(validateDateOfBirthSpy).not.toHaveBeenCalled(); @@ -84,7 +87,7 @@ describe("DOB (valid UUID)", () => { const error = await screen.findByRole("alert"); // THEN - expect(error.textContent).toEqual( + expect(error).toHaveTextContent( "Error: Date of birth must be after 1900 and before the current year" ); expect(validateDateOfBirthSpy).not.toHaveBeenCalled(); @@ -99,7 +102,7 @@ describe("DOB (valid UUID)", () => { const error = await screen.findByRole("alert"); // THEN - expect(error.textContent).toEqual( + expect(error).toHaveTextContent( "Error: Date of birth must be after 1900 and before the current year" ); expect(validateDateOfBirthSpy).not.toHaveBeenCalled(); @@ -115,7 +118,7 @@ describe("DOB (valid UUID)", () => { const error = await screen.findByRole("alert"); // THEN - expect(error.textContent).toEqual( + expect(error).toHaveTextContent( "Error: The date of birth entered is incorrect" ); expect(validateDateOfBirthSpy).toHaveBeenCalled(); @@ -126,9 +129,10 @@ describe("DOB (valid UUID)", () => { userEvent.type(await screen.findByLabelText("Date of birth"), "08/21/1987"); // WHEN - await act(async () => { - userEvent.click(await screen.findByText("Continue")); - }); + userEvent.click(await screen.findByText("Continue")); + await waitForElementToBeRemoved(() => + screen.queryByText("Validating birth date...") + ); // THEN expect(screen.queryByRole("alert")).not.toBeInTheDocument(); @@ -140,9 +144,10 @@ describe("DOB (valid UUID)", () => { userEvent.type(await screen.findByLabelText("Date of birth"), "08/21/1987"); // WHEN - await act(async () => { - userEvent.click(await screen.findByText("Continue")); - }); + userEvent.click(await screen.findByText("Continue")); + await waitForElementToBeRemoved(() => + screen.queryByText("Validating birth date...") + ); // THEN expect( @@ -160,9 +165,10 @@ describe("DOB (valid UUID)", () => { userEvent.type(await screen.findByLabelText("Date of birth"), "08/21/1987"); // WHEN - await act(async () => { - userEvent.click(await screen.findByText("Continue")); - }); + userEvent.click(await screen.findByText("Continue")); + await waitForElementToBeRemoved(() => + screen.queryByText("Validating birth date...") + ); // THEN expect( @@ -187,7 +193,7 @@ describe("DOB (invalid UUID)", () => { const error = await screen.findByRole("alert"); // THEN - expect(error.textContent).toEqual( + expect(error).toHaveTextContent( "Page not foundThis test result link is invalid. Please double check the URL or contact your test provider for the correct link." ); expect(validateDateOfBirthSpy).not.toHaveBeenCalled(); diff --git a/frontend/src/patientApp/timeOfTest/PatientFormContainer.test.tsx b/frontend/src/patientApp/timeOfTest/PatientFormContainer.test.tsx index 382bf56e29..b251689931 100644 --- a/frontend/src/patientApp/timeOfTest/PatientFormContainer.test.tsx +++ b/frontend/src/patientApp/timeOfTest/PatientFormContainer.test.tsx @@ -1,5 +1,4 @@ -import renderer from "react-test-renderer"; -import { render, screen, cleanup } from "@testing-library/react"; +import { render, screen } from "@testing-library/react"; import { MockedProvider } from "@apollo/client/testing"; import { Provider } from "react-redux"; import configureStore from "redux-mock-store"; @@ -13,7 +12,7 @@ jest.mock("@trussworks/react-uswds", () => ({ const mockStore = configureStore([]); jest.mock("react-router-dom", () => ({ - Prompt: (props: any) => <>, + Prompt: (_props: any) => <>, useHistory: () => ({ listen: jest.fn(), push: jest.fn(), @@ -21,9 +20,7 @@ jest.mock("react-router-dom", () => ({ })); describe("PatientFormContainer", () => { - afterEach(cleanup); - - it("snapshot", () => { + it("renders", () => { jest .useFakeTimers("modern") .setSystemTime(new Date("2021-08-01").getTime()); @@ -39,7 +36,7 @@ describe("PatientFormContainer", () => { }, facilities: [], }); - const component = renderer.create( + render( @@ -47,9 +44,11 @@ describe("PatientFormContainer", () => { ); - expect(component.toJSON()).toMatchSnapshot(); + expect( + screen.getAllByText("Profile information", { exact: false })[0] + ).toBeInTheDocument(); }); - describe("testing-library/react renderer", () => { + describe("renders the correct content", () => { window.scrollTo = jest.fn(); beforeEach(() => { diff --git a/frontend/src/patientApp/timeOfTest/PatientFormContainer.tsx b/frontend/src/patientApp/timeOfTest/PatientFormContainer.tsx index a6cd3cec19..315c191696 100644 --- a/frontend/src/patientApp/timeOfTest/PatientFormContainer.tsx +++ b/frontend/src/patientApp/timeOfTest/PatientFormContainer.tsx @@ -45,10 +45,6 @@ const PatientFormContainer = () => { state, county, zipCode, - firstName, - middleName, - lastName, - birthDate, ...withoutAddress } = person; const updatedPatientFromApi = await PxpApi.updatePatient( diff --git a/frontend/src/patientApp/timeOfTest/PatientProfile.test.tsx b/frontend/src/patientApp/timeOfTest/PatientProfile.test.tsx index 330cc1cb66..38b4d0ea0b 100644 --- a/frontend/src/patientApp/timeOfTest/PatientProfile.test.tsx +++ b/frontend/src/patientApp/timeOfTest/PatientProfile.test.tsx @@ -1,7 +1,7 @@ -import renderer from "react-test-renderer"; import { Provider } from "react-redux"; import configureStore from "redux-mock-store"; import { MemoryRouter } from "react-router"; +import { render, screen } from "@testing-library/react"; import PatientProfile from "./PatientProfile"; @@ -15,7 +15,7 @@ const mockContainer = (store: any, patient: any) => ( ); describe("PatientProfile", () => { - it("snapshot", () => { + it("renders", () => { const patient = { firstName: "Jane", lastName: "Doe", @@ -24,14 +24,16 @@ describe("PatientProfile", () => { const store = mockStore({ plid: "foo", }); - const component = renderer.create(mockContainer(store, patient)); - expect(component.toJSON()).toMatchSnapshot(); + render(mockContainer(store, patient)); + expect( + screen.getByText("General information", { exact: false }) + ).toBeInTheDocument(); }); it("should redirect to '/' if no patient", () => { const store = mockStore({ plid: "foo", }); - renderer.create(mockContainer(store, null)); + render(mockContainer(store, null)); // eslint-disable-next-line no-restricted-globals expect(location.pathname).toEqual("/"); }); diff --git a/frontend/src/patientApp/timeOfTest/PatientProfileContainer.test.tsx b/frontend/src/patientApp/timeOfTest/PatientProfileContainer.test.tsx index bf58f3665a..7e42366dfb 100644 --- a/frontend/src/patientApp/timeOfTest/PatientProfileContainer.test.tsx +++ b/frontend/src/patientApp/timeOfTest/PatientProfileContainer.test.tsx @@ -1,5 +1,5 @@ -import renderer from "react-test-renderer"; import { MockedProvider } from "@apollo/client/testing"; +import { render, screen } from "@testing-library/react"; import { Provider } from "react-redux"; import configureStore from "redux-mock-store"; @@ -15,7 +15,7 @@ jest.mock("react-router-dom", () => ({ })); describe("PatientProfileContainer", () => { - it("snapshot", () => { + it("renders", () => { const store = mockStore({ patient: { residentCongregateSetting: true, @@ -25,7 +25,7 @@ describe("PatientProfileContainer", () => { }, plid: "definitely not null I promise", }); - const component = renderer.create( + render( @@ -33,6 +33,8 @@ describe("PatientProfileContainer", () => { ); - expect(component.toJSON()).toMatchSnapshot(); + expect( + screen.getAllByText("Profile information", { exact: false })[0] + ).toBeInTheDocument(); }); }); diff --git a/frontend/src/patientApp/timeOfTest/TermsOfService.test.tsx b/frontend/src/patientApp/timeOfTest/TermsOfService.test.tsx index e53744f8f9..276b71b4da 100644 --- a/frontend/src/patientApp/timeOfTest/TermsOfService.test.tsx +++ b/frontend/src/patientApp/timeOfTest/TermsOfService.test.tsx @@ -1,21 +1,22 @@ -import renderer from "react-test-renderer"; import { MockedProvider } from "@apollo/client/testing"; +import { render, screen } from "@testing-library/react"; import { Provider } from "react-redux"; import configureStore from "redux-mock-store"; import { Router } from "react-router-dom"; import { createMemoryHistory } from "history"; import TermsOfService from "./TermsOfService"; + import "../../i18n"; const mockStore = configureStore([]); describe("TermsOfService", () => { - it("snapshot", () => { + it("renders", () => { const store = mockStore({ plid: "foo", }); - const component = renderer.create( + render( @@ -25,6 +26,6 @@ describe("TermsOfService", () => { ); - expect(component.toJSON()).toMatchSnapshot(); + expect(screen.getByText("Terms of service")).toBeInTheDocument(); }); }); diff --git a/frontend/src/patientApp/timeOfTest/TestResult.test.tsx b/frontend/src/patientApp/timeOfTest/TestResult.test.tsx index 7d0aba0096..b18ab7d5ba 100644 --- a/frontend/src/patientApp/timeOfTest/TestResult.test.tsx +++ b/frontend/src/patientApp/timeOfTest/TestResult.test.tsx @@ -2,7 +2,7 @@ import { Provider } from "react-redux"; import configureStore from "redux-mock-store"; import { Router } from "react-router-dom"; import { createMemoryHistory } from "history"; -import { render } from "@testing-library/react"; +import { render, screen } from "@testing-library/react"; import TestResult from "./TestResult"; import "../../i18n"; @@ -23,7 +23,7 @@ describe("TestResult", () => { }, }, }); - const { container, getByText } = render( + render( @@ -31,11 +31,10 @@ describe("TestResult", () => { ); - expect(getByText("SARS-CoV-2 result")).toBeInTheDocument(); - expect(getByText("Bob Barker")).toBeInTheDocument(); - expect(getByText("Test result")).toBeInTheDocument(); - expect(getByText("Positive")).toBeInTheDocument(); - expect(container).toMatchSnapshot(); + expect(screen.getByText("SARS-CoV-2 result")).toBeInTheDocument(); + expect(screen.getByText("Bob Barker")).toBeInTheDocument(); + expect(screen.getByText("Test result")).toBeInTheDocument(); + expect(screen.getByText("Positive")).toBeInTheDocument(); }); it("should show a negative result", () => { const store = mockStore({ @@ -50,7 +49,7 @@ describe("TestResult", () => { }, }, }); - const { container, getByText } = render( + render( @@ -58,11 +57,10 @@ describe("TestResult", () => { ); - expect(getByText("SARS-CoV-2 result")).toBeInTheDocument(); - expect(getByText("Bob Barker")).toBeInTheDocument(); - expect(getByText("Test result")).toBeInTheDocument(); - expect(getByText("Negative")).toBeInTheDocument(); - expect(container).toMatchSnapshot(); + expect(screen.getByText("SARS-CoV-2 result")).toBeInTheDocument(); + expect(screen.getByText("Bob Barker")).toBeInTheDocument(); + expect(screen.getByText("Test result")).toBeInTheDocument(); + expect(screen.getByText("Negative")).toBeInTheDocument(); }); it("should show an inconclusive result", () => { const store = mockStore({ @@ -77,7 +75,7 @@ describe("TestResult", () => { }, }, }); - const { container, getByText } = render( + render( @@ -85,10 +83,9 @@ describe("TestResult", () => { ); - expect(getByText("SARS-CoV-2 result")).toBeInTheDocument(); - expect(getByText("Bob Barker")).toBeInTheDocument(); - expect(getByText("Test result")).toBeInTheDocument(); - expect(getByText("Inconclusive")).toBeInTheDocument(); - expect(container).toMatchSnapshot(); + expect(screen.getByText("SARS-CoV-2 result")).toBeInTheDocument(); + expect(screen.getByText("Bob Barker")).toBeInTheDocument(); + expect(screen.getByText("Test result")).toBeInTheDocument(); + expect(screen.getByText("Inconclusive")).toBeInTheDocument(); }); }); diff --git a/frontend/src/patientApp/timeOfTest/__snapshots__/AoEPatientFormContainer.test.tsx.snap b/frontend/src/patientApp/timeOfTest/__snapshots__/AoEPatientFormContainer.test.tsx.snap deleted file mode 100644 index 933d006b22..0000000000 --- a/frontend/src/patientApp/timeOfTest/__snapshots__/AoEPatientFormContainer.test.tsx.snap +++ /dev/null @@ -1,863 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`AoEPatientFormContainer snapshot 1`] = ` -
    -
    -
    -
      -
    1. - - Profile information - - - completed - - -
    2. -
    3. - - Symptoms and history - - - completed - - -
    4. -
    -
    -

    - - - Step - - - 2 - - - of - 2 - - - - Symptoms and history - -

    -
    -
    -
    -
    -

    - Required fields are marked with an asterisk - ( - - * - - ). -

    -
    -
    - - Results - -
    -
    -
    - - Would you like to receive a copy of your results via text message? - - - You’re responsible for entering the correct contact information, following applicable federal and state laws. - -
    -
    - - -
    -
    - - -
    -
    -
    -
    -
    -
    -
    -
    - - Would you like to receive a copy of your results via email? - - - You’re responsible for entering the correct contact information, following applicable federal and state laws. - -
    -
    - - -
    -
    - - -
    -
    -
    -
    -
    -
    -
    -
    -
    - - Symptoms - -
    -
    -
    - - Are you experiencing any of the following symptoms? - - - * - - -
    -
    - - -
    -
    -
    -
    -
    -
    -
    - - What are your symptoms? - -
    -
    - - -
    -
    - - -
    -
    - - -
    -
    - - -
    -
    - - -
    -
    - - -
    -
    - - -
    -
    - - -
    -
    - - -
    -
    - - -
    -
    - - -
    -
    - - -
    -
    - - -
    -
    - - -
    -
    - - -
    -
    - - -
    -
    - - -
    -
    -
    -
    -
    -
    - - - mm/dd/yyyy - -
    - -
    - - - -
    -
    -
    -
    -
    -
    - - Pregnancy - -
    -
    - - Are you currently pregnant? - -
    -
    - - -
    -
    - - -
    -
    - - -
    -
    -
    -
    -
    -
    -
    -
    -
    - -
    -
    -
    -
    -
    -`; diff --git a/frontend/src/patientApp/timeOfTest/__snapshots__/PatientFormContainer.test.tsx.snap b/frontend/src/patientApp/timeOfTest/__snapshots__/PatientFormContainer.test.tsx.snap deleted file mode 100644 index b337e71695..0000000000 --- a/frontend/src/patientApp/timeOfTest/__snapshots__/PatientFormContainer.test.tsx.snap +++ /dev/null @@ -1,2528 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`PatientFormContainer snapshot 1`] = ` -
    -
    -
    -
      -
    1. - - Profile information - - - completed - - -
    2. -
    3. - - Symptoms and history - - - completed - - -
    4. -
    -
    -

    - - - Step - - - 1 - - - of - 2 - - - - Profile information - -

    -
    -
    -
    -
    -
    -
    - - General information - -

    - Required fields are marked with an asterisk - ( - - * - - ). -

    -
    -
    - - -
    -
    - - -
    -
    - - -
    -
    -
    -
    - - -
    -
    - -
    -
    -
    -
    - - -
    -
    -
    -
    -
    -
    - - Contact information - -

    - You're responsible for entering the correct contact information, following applicable federal and state laws. -

    -
    -
    -
    -
    - - -
    -
    -
    -
    - - Phone type - - - * - - -
    -
    - - -
    -
    - - -
    -
    -
    -
    -
    - -
    -
    -
    -
    -
    -
    - - -
    -
    - -
    -
    -
    - -
    -
    -
    -
    - - -
    -
    -
    -
    - - -
    -
    -
    -
    - - -
    -
    -
    -
    - - -
    -
    - - -
    -
    -
    -
    -
    -
    - - Demographics - -

    - This information is collected as part of public health efforts to recognize and address inequality in health outcomes. -

    -
    -
    - - Race - -
    -
    - - -
    -
    - - -
    -
    - - -
    -
    - - -
    -
    - - -
    -
    - - -
    -
    - - -
    -
    -
    -
    -
    - -
    -
    -
    - - Are you Hispanic or Latino? - -
    -
    - - -
    -
    - - -
    -
    - - -
    -
    -
    -
    -
    -
    - - Sex assigned at birth - - - This is usually the gender that is written on your original birth certificate. - -
    -
    - - -
    -
    - - -
    -
    - - -
    -
    - - -
    -
    -
    -
    -
    -
    -
    -
    - - Other - -
    -
    - - Are you a resident in a congregate living setting? - - - For example: nursing home, group home, prison, jail, or military - -
    -
    - - -
    -
    - - -
    -
    - - -
    -
    -
    -
    -
    -
    - - Are you a health care worker? - -
    -
    - - -
    -
    - - -
    -
    - - -
    -
    -
    -
    -
    -
    -
    - - -
    -
    -
    -
    -
    -`; diff --git a/frontend/src/patientApp/timeOfTest/__snapshots__/PatientProfile.test.tsx.snap b/frontend/src/patientApp/timeOfTest/__snapshots__/PatientProfile.test.tsx.snap deleted file mode 100644 index 6bf492f39a..0000000000 --- a/frontend/src/patientApp/timeOfTest/__snapshots__/PatientProfile.test.tsx.snap +++ /dev/null @@ -1,130 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`PatientProfile snapshot 1`] = ` -
    -

    - General information -

    -

    - Name -

    -

    - Jane Doe -

    -

    - Preferred language -

    -

    - Not provided -

    -

    - Date of birth -

    -

    - Not provided -

    -

    - Phone number -

    -

    - Not provided -

    -

    - Address -

    -

    - - 24 Dreary Ln - - - undefinedundefined - -

    -

    - Email address -

    -

    - Not provided -

    -

    - Demographics -

    -

    - Race -

    -

    - Not provided -

    -

    - Ethnicity -

    -

    - Not provided -

    -

    - Tribal affiliation -

    -

    - Not provided -

    -

    - Sex assigned at birth -

    -

    - Not provided -

    -

    - Other -

    -

    - Are you a resident in a congregate living setting? -

    -

    - Not provided -

    -

    - Are you a health care worker? -

    -

    - Not provided -

    -
    -`; diff --git a/frontend/src/patientApp/timeOfTest/__snapshots__/PatientProfileContainer.test.tsx.snap b/frontend/src/patientApp/timeOfTest/__snapshots__/PatientProfileContainer.test.tsx.snap deleted file mode 100644 index eef1aed7ca..0000000000 --- a/frontend/src/patientApp/timeOfTest/__snapshots__/PatientProfileContainer.test.tsx.snap +++ /dev/null @@ -1,232 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`PatientProfileContainer snapshot 1`] = ` -
    -
    -
    -
      -
    1. - - Profile information - - - completed - - -
    2. -
    3. - - Symptoms and history - - - completed - - -
    4. -
    -
    -

    - - - Step - - - 1 - - - of - 2 - - - - Profile information - -

    -
    -
    -
    -

    - General information -

    -

    - Name -

    -

    - undefined -

    -

    - Preferred language -

    -

    - Not provided -

    -

    - Date of birth -

    -

    - Not provided -

    -

    - Phone number -

    -

    - Not provided -

    -

    - Address -

    -

    - - 8 Pine Ct - - - undefinedundefined - -

    -

    - Email address -

    -

    - Not provided -

    -

    - Demographics -

    -

    - Race -

    -

    - Not provided -

    -

    - Ethnicity -

    -

    - Not provided -

    -

    - Tribal affiliation -

    -

    - Not provided -

    -

    - Sex assigned at birth -

    -

    - Not provided -

    -

    - Other -

    -

    - Are you a resident in a congregate living setting? -

    -

    - Yes -

    -

    - Are you a health care worker? -

    -

    - Yes -

    -
    -
    - -
    - -
    -
    -`; diff --git a/frontend/src/patientApp/timeOfTest/__snapshots__/TermsOfService.test.tsx.snap b/frontend/src/patientApp/timeOfTest/__snapshots__/TermsOfService.test.tsx.snap deleted file mode 100644 index 7df7b398b4..0000000000 --- a/frontend/src/patientApp/timeOfTest/__snapshots__/TermsOfService.test.tsx.snap +++ /dev/null @@ -1,293 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`TermsOfService snapshot 1`] = ` -
    -
    -

    - Terms of service -

    -

    - This testing site uses - - SimpleReport - - to manage COVID-19 testing and reporting. The terms below explain SimpleReport’s policies and terms of service. -

    -
    -

    - 12/4/2020 -

    -

    - As a User accessing or using SimpleReport (Application) provided by the Centers for Disease Control and Prevention (CDC) and the U.S. Department of Health and Human Services (HHS), in a CDC cloud environment (“CDC Platform”), you acknowledge and agree that you are solely responsible for and shall abide by these Terms of Service, as well as any relevant sections of - - CDC’s Privacy Policies - - (collectively, Terms). -

    -

    - Scope -

    -

    - SimpleReport is a free tool that makes it easy for facilities such as health care settings or schools to record and quickly transmit public health data to public health departments. It also allows those facilities to enable individuals or guardians to access relevant test results. This Application is being provided by HHS and CDC to enable an Entity to record its data intake workflow, for record keeping needs and to transmit relevant and necessary data to state, local, tribal, and territorial public health authorities (STLT Public Health Agencies) in furtherance of public health surveillance and response activities. It also allows the Entity to designate certain users of the data, as set out in these Terms. The Application through which the Entity and any users interact with relevant public health data is subject to these Terms. Use of the Application constitutes acceptance of these Terms. -

    -

    - Definitions -

    -
      -
    • - Entity -
    • -
    -

    - A health care provider or facility; testing site; a state, local, tribal, and territorial public health authority (STLT Public Health Agency); or other organization that is enrolled in and using Simple Report to record and/or transmit data. -

    -
      -
    • - User -
    • -
    -

    - An individual whose personal data is being reported via Simple Report (Individual User), or an individual authorized to act on behalf of the Entity under these Terms (Entity User or Entity Administrator). Simple Report will only designate one User from the Entity as the Entity Administrator. Entity Administrators will have more detailed identity verification than general Entity Users. Once the Entity Administrator has their identity verified, the Entity Administrator can add other general Entity Users or Individual Users to the Application. All roles are referred to as “User” for the purposes of these Terms, unless otherwise indicated. -

    -

    - Data rights and usage -

    -

    - Accounts/Registration -

    -
      -
    • - For entity users -
    • -
    -

    - If you are using the Application on behalf of an Entity as either an Entity Administrator or Entity User, you represent and warrant that you have authority to bind that Entity to the Terms and by accepting the Terms, you are doing so on behalf of that Entity (and all references to “you” in the Terms refer to you and that Entity). -

    -

    - In order to access the Application, as part of the registration process for the Application, and for your continued use of the Application, you may be required to provide certain information (such as identification or contact details). Any such information you give to CDC or HHS must be accurate and up-to-date. You must inform us promptly of any updates by updating your information in the Application or by emailing - - support@simplereport.gov - - so that we can keep you informed of any changes to the Application or these Terms which may impact your usage of the Application. We may use the contact information you provide to contact you regarding usability research for ongoing product and service improvement. Upon Entity registration and the creation of Entity User accounts within the Application, credentials (such as passwords, keys, tokens, and Entity and Entity User identifications (IDs)) will be issued to you by HHS or CDC. These credentials are intended to be used only by you and to identify any software or APIs which you are using. You agree to keep your credentials confidential and make reasonable efforts to prevent and discourage other persons from using your credentials. -

    -
      -
    • - For entity administrators -
    • -
    -

    - The Entity Administrator agrees to verify the identity of other Entity Users who are added and to inactivate any other Entity Users who should no longer have access. The Administrator also agrees to set permissions appropriately to determine the minimum access necessary for each other Entity User to complete their required job duties. -

    -
      -
    • - For individual users -
    • -
    -

    - Entity Administrators will grant Individual Users access to the Application. Individual Users can use the Application to access and review their own information or information about others as may be permitted by applicable law (e.g., on behalf of a minor or otherwise as a guardian). As noted above, all Users agree to accept and comply with these Terms once you register and use the Application. -

    -

    - Privacy -

    -

    - You may use the Application to search, display, analyze, retrieve, view and/or otherwise ‘get’ information from data you are sending (or for Individual Users, for data being sent about you) via the Application and the Platform. Please note that the data which you are recording, transmitting or accessing via the Application may be subject to the Privacy Act of 1974, the Health Insurance Portability and Accountability Act of 1996 (HIPAA), and other laws, and requires special safeguarding. By accessing and using the Application, you agree to strictly abide by all applicable federal and state laws regarding the collection, use, protection and disclosure of information obtained or sent through the Application. Where Individual Users may be accessing the information on behalf of a minor or otherwise as a guardian, Entity Users and Administrator Users agree to assume full responsibility for designating the correct Individual User contact information within the Application, in accordance with applicable law. If you would like more information about the application of the Privacy Act at CDC, - - click here - - . -

    -

    - For purposes of use of this Application, if you are a HIPAA-covered entity or acting on behalf of one as a business associate or if the data is maintained by you in a HIPAA-covered designated record set, you further acknowledge that you will abide by applicable HIPAA regulations (45 CFR Parts 160 and 164) for purposes of appropriate storage, transmission, use and disclosure of any protected health information. -

    -

    - Use of data -

    -

    - This Application is being provided in order to allow for the recording of Entity data, support Entity’s workflow, for record keeping purposes, and for transmitting relevant data to STLT Public Health Agencies in furtherance of public health surveillance and response activities. HHS and CDC acknowledge that though CDC is providing the Platform, CDC does not intend to access the data nor does it intend to review or analyze this data. As such, CDC does not intend to take custody or control of data sent via the Application. Entity and Individual Users acknowledge and agree that CDC and Administrative Users may manage the data sent via the Application for purposes of operating the CDC Platform (which includes verifying user identity) and transmitting to and facilitating use by STLT Public Health Agencies of such data. Except as may be required by applicable federal law, CDC may not release the data sent via the Application for other purposes than described below. -

    -

    - Sharing of data -

    -

    - Data recorded and stored in the Application by the Entity is for use by the Entity as needed for workflow, record keeping, and reporting purposes. Data recorded and stored by the Entity in the Application will be automatically transmitted to the appropriate STLT Public Health Agency based on both the Entity ZIP code and the Patient’s ZIP code, including, for coronavirus disease 2019 test results, all relevant fields as defined in the - - HHS COVID-19 Laboratory Reporting Requirements - - . By entering results that are being transmitted to the relevant STLT Public Health Agency or Agencies, the Entity attests that it is authorized to report the data via the Application. Though CDC will not actively access and obtain data from the Application, Entity, directly or in coordination with the relevant STLT Public Health Agency, may decide to use the Application to send deidentified or other as may be determined by Entity, to CDC; such data sent to CDC will be maintained consistent with applicable federal laws. -

    -

    - Other responsibilities -

    -
      -
    • - For all users: -
    • -
        -
      • - You will be fully accountable for all data you submit and will cooperate with CDC or its agents in the event that CDC has a security concern with respect to any inquiry, submission, or receipt of data to or from CDC. -
      • -
      • - You will promptly inform CDC in the event you identify misuse of individually identifiable health information or protected health information you submit and/or access from the CDC Platform. -
      • -
      • - You will promptly inform CDC in the event that you can no longer comply with any of the provisions set out in these Terms. -
      • -
      • - You will immediately cease Application use when you no longer meet any of the terms of these Terms. -
      • -
      -
    • - For entity administrators and entity users: -
    • -
        -
      • - You must adhere to the basic desktop security measures to ensure the security of any individually identifiable information or protected health information to which you have access in the Application. -
      • -
      • - As may be required by applicable law you agree to obtain consent from and/or notify individuals whose data will be input into the Application that their personal information will be collected and used for public health purposes. -
      • -
      • - When major changes are made to the Application and/or Platform (e.g., disclosure and/or data uses have changed since the notice at the time of original collection), you will be notified by email, and are responsible for notifying and obtaining consent from individuals whose individually identifiable or protected health information is in the Application. -
      • -
      • - In the unlikely event of a breach, you will be required to notify individuals whose individually identifiable or protected health information is in the Application and have been impacted by the breach. Assistance may be offered by CDC to aid in this process. -
      • -
      • - You are required to ensure that anyone using the Application has been trained on handling sensitive and personal information. -
      • -
      -
    -

    - Service management -

    -

    - Right to Limit -

    -

    - Your use of the Application may be subject to certain limitations on access or use as set forth within these Terms or otherwise provided by CDC. These limitations are designed to manage the load on the system, promote equitable access, and ensure appropriate privacy protections and these limitations may be adjusted without notice, as deemed necessary by CDC. If CDC reasonably believes that you have attempted to exceed or circumvent these limits, your ability to use the Application may be temporarily or permanently blocked. CDC may monitor your use of the Application to improve the service or to ensure compliance with these Terms and reserves the right to deny any User access to the Application at its reasonable discretion. -

    -

    - Service termination -

    -

    - If you wish to terminate your access to and use of the Application, you may do so by deactivating your account (such as by contacting your Entity Administrator) or by refraining from further use of the Application. -

    -

    - CDC reserves the right (though not the obligation) to: (1) refuse to provide the Application to you, if it is CDC’s opinion that use violates any federal law or CDC policy; or (2) terminate or deny you access to and use of all or part of the Application at any time for any reason which in CDC’s sole discretion it deems necessary, including to prevent violation of federal law or CDC policy. You may petition CDC to regain access to the Application through the support email address provided by CDC for the Application. If CDC determines in its sole discretion that the circumstances which led to the refusal to provide the Application or terminate access to the Application no longer exist, then CDC may restore your access. All provisions of these Terms, which by their nature should survive termination, shall survive termination including, without limitation, warranty disclaimers, and limitations of liability. -

    -

    - Intellectual property – License grant and restrictions -

    -

    - The Application provided to User are for User’s use. User may not modify, copy, distribute, transmit, display, perform, reproduce, publish, license, create derivative works from, transfer, or sell any information, software, products, or services obtained from CDC. Materials provided by CDC are either owned by or the licensed property of the United States Department of Health and Human Services (“HHS”) and the Centers for Disease Control and Prevention (CDC). HHS/CDC grants to you a limited, non-exclusive, non-transferable license to access the Application in the United States for the uses set forth in these Terms. -

    -

    - Disclaimer of warranties -

    -

    - The Application Platform is provided “as is” and on an “as-available” basis. While CDC will do its best to ensure the service is available and functional at all times, CDC hereby disclaims all warranties of any kind, express or implied, including without limitation the warranties of merchantability, fitness for a particular purpose, and non-infringement. CDC makes no warranty that data will be error free or that access thereto will be continuous or uninterrupted. -

    -

    - Limitations on liability -

    -

    - To the extent allowed by law, HHS and CDC will not be liable, with respect to any subject matter of these Terms or your use of the Application under any contract, negligence, strict liability or other legal or equitable theory for: (1) any personal injury, or any special, incidental, indirect or consequential damages; (2) the cost of procurement of substitute products or services; or (3) for loss of profits, interruption of use or loss or corruption of data or any other commercial damages or losses. -

    -

    - HHS and CDC are not responsible for confidentiality or any information shared by the Entity or other User of the Application. -

    -

    - Disputes, choice of law, venue, and conflicts -

    -

    - Any disputes arising out of these Terms and access to or use of the Application shall be governed by applicable United States Federal law. You further agree and consent to the jurisdiction of the Federal Courts located within the District of Columbia and the courts of appeal therefrom and waive any claim of lack of jurisdiction or forum non conveniens. -

    -

    - Indemnification -

    -

    - You agree to indemnify and hold harmless HHS, including CDC, its contractors, employees, agents, and the like, from and against any and all claims and expenses, including attorney’s fees, arising out of your use of the Application, including but not limited to violation of these Terms. -

    -

    - No waiver of rights -

    -

    - CDC’s failure to exercise or enforce any right or provision of these Terms shall not constitute waiver of such right or provision. -

    -

    - Data analytics and monitoring metrics -

    -

    - While using the Application, certain general data analytics on the usage patterns and performance of the Application may be gathered and stored automatically to assist with design and development of the Application. This general usage data is not linked to an individual’s identity but IP address and device information may be included. Transactions are audited and stored for site monitoring, performance, and troubleshooting and may be tied to the individual performing an activity. Any such data will be maintained consistent with applicable federal laws. -

    -
    -

    - By agreeing, you consent to our terms of service. -

    - -
    -
    -`; diff --git a/frontend/src/patientApp/timeOfTest/__snapshots__/TestResult.test.tsx.snap b/frontend/src/patientApp/timeOfTest/__snapshots__/TestResult.test.tsx.snap deleted file mode 100644 index 3b9329ea52..0000000000 --- a/frontend/src/patientApp/timeOfTest/__snapshots__/TestResult.test.tsx.snap +++ /dev/null @@ -1,367 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`TestResult should show a negative result 1`] = ` -
    -
    -
    -
    -

    - SARS-CoV-2 result -

    -

    - Patient -

    -

    - Bob Barker -

    -
    -
    -

    - Test result -

    -

    - Negative -

    -
    -
    -

    - Test date -

    -

    - 8/27/2020 -

    -
    -
    -

    - Test device -

    -

    -

    - What does my result mean? -

    -

    - Contact your health care provider to decide if additional testing is needed, especially if you experience any of these symptoms: -

    -
      -
    • - Fever or chills -
    • -
    • - Cough -
    • -
    • - Shortness of breath or difficulty breathing -
    • -
    • - Fatigue -
    • -
    • - Muscle or body aches -
    • -
    • - Headache -
    • -
    • - Loss of taste or smell -
    • -
    • - Sore throat -
    • -
    • - Congestion or runny nose -
    • -
    • - Nausea or vomiting -
    • -
    • - Diarrhea -
    • -
    -

    - For more information, please visit the - - Centers for Disease Control and Prevention (CDC) website - - or contact your local health department. -

    -
    -
    -
    -
    -`; - -exports[`TestResult should show a positive result 1`] = ` -
    -
    -
    -
    -

    - SARS-CoV-2 result -

    -

    - Patient -

    -

    - Bob Barker -

    -
    -
    -

    - Test result -

    -

    - Positive -

    -
    -
    -

    - Test date -

    -

    - 8/27/2020 -

    -
    -
    -

    - Test device -

    -

    - Testing device -

    -

    - What does my result mean? -

    -

    - Most people who get COVID-19 will be able to recover at home. Make sure to follow CDC guidelines for people who are recovering at home and their caregivers, including: -

    -
      -
    • - Stay home when you are sick, except to get medical care. -
    • -
    • - Self isolate for 10 full days after symptoms first appeared (or starting the day after you had your test, if you have no symptoms). -
    • -
    • - If you are self isolating at home where others live, use a separate room and bathroom for sick household members (if possible). Clean any shared rooms as needed, to avoid transmitting the virus. -
    • -
    • - Wash your hands often with soap and water for at least 20 seconds, especially after blowing your nose, coughing, or sneezing; going to the bathroom; and before eating or preparing food. -
    • -
    • - If soap and water are not available, use an alcohol-based hand sanitizer with at least 60% alcohol. -
    • -
    • - Have a supply of clean, disposable face masks. Everyone, no matter their COVID-19 diagnosis, should wear face masks while in the home. -
    • -
    -

    - Watch for symptoms and - - learn when to seek emergency medical attention - - . If someone is showing any of these signs, seek emergency medical care immediately: -

    -
      -
    • - Trouble breathing -
    • -
    • - Persistent chest pain/pressure -
    • -
    • - Confusion -
    • -
    • - Inability to wake or stay awake -
    • -
    • - Bluish lips or face -
    • -
    -

    - Call 911 or call ahead to your local emergency room: Notify the operator that you are seeking care for someone who has or may have COVID-19. -

    -

    - Getting a positive COVID-19 test result can be difficult news, so it’s important to - - take steps to cope with stress - - during this time - . Reach out to your support system and make a phone or video appointment with a mental health professional if needed. -

    -

    - For more information, please visit the - - Centers for Disease Control and Prevention (CDC) website - - or contact your local health department. -

    -
    -
    -
    -
    -`; - -exports[`TestResult should show an inconclusive result 1`] = ` -
    -
    -
    -
    -

    - SARS-CoV-2 result -

    -

    - Patient -

    -

    - Bob Barker -

    -
    -
    -

    - Test result -

    -

    - Inconclusive -

    -
    -
    -

    - Test date -

    -

    - 8/27/2020 -

    -
    -
    -

    - Test device -

    -

    -

    - What does my result mean? -

    -

    - An inconclusive result is neither positive nor negative. This can happen because of problems with the sample collection, a very early-stage COVID-19 infection, or for patients with COVID-19 that are close to recovery. With an inconclusive result, collecting and testing another sample is recommended. -

    -

    - Please make an appointment for another test as soon as possible. If you’ve gotten tested due to COVID-19 symptoms, it is recommended that you self-isolate until you get your new test results. -

    -

    - For more information, please visit the - - Centers for Disease Control and Prevention (CDC) website - - or contact your local health department. -

    -
    -
    -
    -
    -`; diff --git a/frontend/src/setupTests.js b/frontend/src/setupTests.js index b4bb5e4919..966b46c4b3 100644 --- a/frontend/src/setupTests.js +++ b/frontend/src/setupTests.js @@ -4,6 +4,8 @@ // learn more: https://github.com/testing-library/jest-dom import "@testing-library/jest-dom/extend-expect"; import fetchMock from "jest-fetch-mock"; +import ReactModal from "react-modal"; +import moment from "moment"; fetchMock.enableMocks(); @@ -15,3 +17,12 @@ jest.mock("@microsoft/applicationinsights-react-js", () => { ReactPlugin: Object, }; }); + +ReactModal.setAppElement("*"); // suppresses modal-related test warnings. + +// Disable moment warnings +moment.suppressDeprecationWarnings = true; + +// This prevents tests from timing out and causing this error in CI: +// TypeError: Cannot read property 'createEvent' of null +jest.setTimeout(30000); diff --git a/frontend/yarn.lock b/frontend/yarn.lock index a7990b18d0..974e446f22 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -2805,6 +2805,13 @@ dependencies: regenerator-runtime "^0.13.4" +"@babel/runtime@^7.9.6": + version "7.16.3" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.16.3.tgz#b86f0db02a04187a3c17caa77de69840165d42d5" + integrity sha512-WBwekcqacdY2e9AF/Q7WLFUWmdJGJTkbjqTjoMDgXkVZ3ZRUvOPsLb5KdwISoQVsbP+DQzVZW4Zhci0DvpbNTQ== + dependencies: + regenerator-runtime "^0.13.4" + "@babel/template@^7.10.4", "@babel/template@^7.12.7", "@babel/template@^7.3.3": version "7.12.7" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.12.7.tgz#c817233696018e39fbb6c491d2fb684e05ed43bc" @@ -5618,6 +5625,11 @@ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.7.tgz#98a993516c859eb0d5c4c8f098317a9ea68db9ad" integrity sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA== +"@types/json-schema@^7.0.9": + version "7.0.9" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d" + integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ== + "@types/json-stable-stringify@^1.0.32": version "1.0.33" resolved "https://registry.yarnpkg.com/@types/json-stable-stringify/-/json-stable-stringify-1.0.33.tgz#099b0712d824d15e2660c20e1c16e6a8381f308c" @@ -5821,13 +5833,6 @@ dependencies: "@types/react" "*" -"@types/react-test-renderer@^17.0.1": - version "17.0.1" - resolved "https://registry.yarnpkg.com/@types/react-test-renderer/-/react-test-renderer-17.0.1.tgz#3120f7d1c157fba9df0118dae20cb0297ee0e06b" - integrity sha512-3Fi2O6Zzq/f3QR9dRnlnHso9bMl7weKCviFmfF6B4LS1Uat6Hkm15k0ZAQuDz+UBq6B3+g+NM6IT2nr5QgPzCw== - dependencies: - "@types/react" "*" - "@types/react-transition-group@^4.4.1": version "4.4.1" resolved "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.1.tgz#e1a3cb278df7f47f17b5082b1b3da17170bd44b1" @@ -6073,6 +6078,18 @@ eslint-scope "^5.0.0" eslint-utils "^2.0.0" +"@typescript-eslint/experimental-utils@^5.0.0": + version "5.4.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-5.4.0.tgz#238a7418d2da3b24874ba35385eb21cc61d2a65e" + integrity sha512-Nz2JDIQUdmIGd6p33A+naQmwfkU5KVTLb/5lTk+tLVTDacZKoGQisj8UCxk7onJcrgjIvr8xWqkYI+DbI3TfXg== + dependencies: + "@types/json-schema" "^7.0.9" + "@typescript-eslint/scope-manager" "5.4.0" + "@typescript-eslint/types" "5.4.0" + "@typescript-eslint/typescript-estree" "5.4.0" + eslint-scope "^5.1.1" + eslint-utils "^3.0.0" + "@typescript-eslint/parser@^4.5.0": version "4.9.1" resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.9.1.tgz#2d74c4db5dd5117379a9659081a4d1ec02629055" @@ -6091,6 +6108,14 @@ "@typescript-eslint/types" "4.9.1" "@typescript-eslint/visitor-keys" "4.9.1" +"@typescript-eslint/scope-manager@5.4.0": + version "5.4.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.4.0.tgz#aaab08415f4a9cf32b870c7750ae8ba4607126a1" + integrity sha512-pRxFjYwoi8R+n+sibjgF9iUiAELU9ihPBtHzocyW8v8D8G8KeQvXTsW7+CBYIyTYsmhtNk50QPGLE3vrvhM5KA== + dependencies: + "@typescript-eslint/types" "5.4.0" + "@typescript-eslint/visitor-keys" "5.4.0" + "@typescript-eslint/types@3.10.1": version "3.10.1" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-3.10.1.tgz#1d7463fa7c32d8a23ab508a803ca2fe26e758727" @@ -6101,6 +6126,11 @@ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.9.1.tgz#a1a7dd80e4e5ac2c593bc458d75dd1edaf77faa2" integrity sha512-fjkT+tXR13ks6Le7JiEdagnwEFc49IkOyys7ueWQ4O8k4quKPwPJudrwlVOJCUQhXo45PrfIvIarcrEjFTNwUA== +"@typescript-eslint/types@5.4.0": + version "5.4.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.4.0.tgz#b1c130f4b381b77bec19696c6e3366f9781ce8f2" + integrity sha512-GjXNpmn+n1LvnttarX+sPD6+S7giO+9LxDIGlRl4wK3a7qMWALOHYuVSZpPTfEIklYjaWuMtfKdeByx0AcaThA== + "@typescript-eslint/typescript-estree@3.10.1": version "3.10.1" resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-3.10.1.tgz#fd0061cc38add4fad45136d654408569f365b853" @@ -6129,6 +6159,19 @@ semver "^7.3.2" tsutils "^3.17.1" +"@typescript-eslint/typescript-estree@5.4.0": + version "5.4.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.4.0.tgz#fe524fb308973c68ebeb7428f3b64499a6ba5fc0" + integrity sha512-nhlNoBdhKuwiLMx6GrybPT3SFILm5Gij2YBdPEPFlYNFAXUJWX6QRgvi/lwVoadaQEFsizohs6aFRMqsXI2ewA== + dependencies: + "@typescript-eslint/types" "5.4.0" + "@typescript-eslint/visitor-keys" "5.4.0" + debug "^4.3.2" + globby "^11.0.4" + is-glob "^4.0.3" + semver "^7.3.5" + tsutils "^3.21.0" + "@typescript-eslint/visitor-keys@3.10.1": version "3.10.1" resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-3.10.1.tgz#cd4274773e3eb63b2e870ac602274487ecd1e931" @@ -6144,6 +6187,14 @@ "@typescript-eslint/types" "4.9.1" eslint-visitor-keys "^2.0.0" +"@typescript-eslint/visitor-keys@5.4.0": + version "5.4.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.4.0.tgz#09bc28efd3621f292fe88c86eef3bf4893364c8c" + integrity sha512-PVbax7MeE7tdLfW5SA0fs8NGVVr+buMPrcj+CWYWPXsZCH8qZ1THufDzbXm1xrZ2b2PA1iENJ0sRq5fuUtvsJg== + dependencies: + "@typescript-eslint/types" "5.4.0" + eslint-visitor-keys "^3.0.0" + "@ungap/global-this@^0.4.2": version "0.4.4" resolved "https://registry.yarnpkg.com/@ungap/global-this/-/global-this-0.4.4.tgz#8a1b2cfcd3e26e079a847daba879308c924dd695" @@ -9153,7 +9204,7 @@ debug@3.2.6: dependencies: ms "^2.1.1" -debug@4, debug@^4.1.1: +debug@4, debug@^4.1.1, debug@^4.3.2: version "4.3.2" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b" integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw== @@ -10136,6 +10187,15 @@ eslint-plugin-import@^2.22.1: resolve "^1.17.0" tsconfig-paths "^3.9.0" +eslint-plugin-jest-dom@^3.9.2: + version "3.9.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-jest-dom/-/eslint-plugin-jest-dom-3.9.2.tgz#2cc200cabb17d1f5535afad9b49d0ca41b2f05eb" + integrity sha512-DKNW6nxYkBvwv36WcYFxapCalGjOGSWUu5PREpDVuXGbEns3S5jhr+mZ5W2N6MxbOWw/2U61C1JVLH31gwVjOQ== + dependencies: + "@babel/runtime" "^7.9.6" + "@testing-library/dom" "^7.28.1" + requireindex "^1.2.0" + eslint-plugin-jest@^24.1.0: version "24.1.3" resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-24.1.3.tgz#fa3db864f06c5623ff43485ca6c0e8fc5fe8ba0c" @@ -10189,6 +10249,25 @@ eslint-plugin-testing-library@^3.9.2: dependencies: "@typescript-eslint/experimental-utils" "^3.10.1" +eslint-plugin-testing-library@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-testing-library/-/eslint-plugin-testing-library-5.0.0.tgz#eb98bcecf44bbdb0df4e78bb58e87a05685b38e0" + integrity sha512-lojlPN8nsb7JTFYhJuLNwwI8kALRC0TBz5JRO1lvV7Ifzqu7IoddjDFRCxeM+0d2/zuEO7Sb5oc7ErDqhd4MBw== + dependencies: + "@typescript-eslint/experimental-utils" "^5.0.0" + +eslint-plugin-unused-imports@1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-1.1.5.tgz#a2b992ef0faf6c6c75c3815cc47bde76739513c2" + integrity sha512-TeV8l8zkLQrq9LBeYFCQmYVIXMjfHgdRQLw7dEZp4ZB3PeR10Y5Uif11heCsHRmhdRIYMoewr1d9ouUHLbLHew== + dependencies: + eslint-rule-composer "^0.3.0" + +eslint-rule-composer@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/eslint-rule-composer/-/eslint-rule-composer-0.3.0.tgz#79320c927b0c5c0d3d3d2b76c8b4a488f25bbaf9" + integrity sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg== + eslint-scope@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.3.tgz#ca03833310f6889a3264781aa82e63eb9cfe7848" @@ -10212,6 +10291,13 @@ eslint-utils@^2.0.0, eslint-utils@^2.1.0: dependencies: eslint-visitor-keys "^1.1.0" +eslint-utils@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672" + integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA== + dependencies: + eslint-visitor-keys "^2.0.0" + eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" @@ -10222,6 +10308,11 @@ eslint-visitor-keys@^2.0.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz#21fdc8fbcd9c795cc0321f0563702095751511a8" integrity sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ== +eslint-visitor-keys@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.1.0.tgz#eee4acea891814cda67a7d8812d9647dd0179af2" + integrity sha512-yWJFpu4DtjsWKkt5GeNBBuZMlNcYVs6vRCLoCVEJrTjaSB6LC98gFipNK/erM2Heg/E8mIK+hXG/pJMLK+eRZA== + eslint-webpack-plugin@^2.5.2: version "2.5.4" resolved "https://registry.yarnpkg.com/eslint-webpack-plugin/-/eslint-webpack-plugin-2.5.4.tgz#473b84932f1a8e2c2b8e66a402d0497bf440b986" @@ -12732,6 +12823,13 @@ is-glob@^3.0.0, is-glob@^3.1.0: dependencies: is-extglob "^2.1.0" +is-glob@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + is-hexadecimal@^1.0.0: version "1.0.4" resolved "https://registry.yarnpkg.com/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz#cc35c97588da4bd49a8eedd6bc4082d44dcb23a7" @@ -17574,16 +17672,16 @@ react-inspector@^5.1.0: is-dom "^1.0.0" prop-types "^15.0.0" -"react-is@^16.12.0 || ^17.0.0", react-is@^17.0.1: - version "17.0.1" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.1.tgz#5b3531bd76a645a4c9fb6e693ed36419e3301339" - integrity sha512-NAnt2iGDXohE5LI7uBnLnqvLQMtzhkiAOLXTmv+qnF9Ky7xAPcX8Up/xWIhxvLVGJvuLiNc4xQLtuqDRzb4fSA== - react-is@^16.13.1, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1, react-is@^16.8.4: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== +react-is@^17.0.1: + version "17.0.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.1.tgz#5b3531bd76a645a4c9fb6e693ed36419e3301339" + integrity sha512-NAnt2iGDXohE5LI7uBnLnqvLQMtzhkiAOLXTmv+qnF9Ky7xAPcX8Up/xWIhxvLVGJvuLiNc4xQLtuqDRzb4fSA== + react-is@^17.0.2: version "17.0.2" resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" @@ -17749,14 +17847,6 @@ react-scripts@^4.0.3: optionalDependencies: fsevents "^2.1.3" -react-shallow-renderer@^16.13.1: - version "16.14.1" - resolved "https://registry.yarnpkg.com/react-shallow-renderer/-/react-shallow-renderer-16.14.1.tgz#bf0d02df8a519a558fd9b8215442efa5c840e124" - integrity sha512-rkIMcQi01/+kxiTE9D3fdS959U1g7gs+/rborw++42m1O9FAQiNI/UNRZExVUoAOprn4umcXf+pFRou8i4zuBg== - dependencies: - object-assign "^4.1.1" - react-is "^16.12.0 || ^17.0.0" - react-sizeme@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/react-sizeme/-/react-sizeme-3.0.1.tgz#4d12f4244e0e6a0fb97253e7af0314dc7c83a5a0" @@ -17778,16 +17868,6 @@ react-syntax-highlighter@^13.5.3: prismjs "^1.21.0" refractor "^3.1.0" -react-test-renderer@^17.0.1: - version "17.0.1" - resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-17.0.1.tgz#3187e636c3063e6ae498aedf21ecf972721574c7" - integrity sha512-/dRae3mj6aObwkjCcxZPlxDFh73XZLgvwhhyON2haZGUEhiaY5EjfAdw+d/rQmlcFwdTpMXCSGVk374QbCTlrA== - dependencies: - object-assign "^4.1.1" - react-is "^17.0.1" - react-shallow-renderer "^16.13.1" - scheduler "^0.20.1" - react-textarea-autosize@^8.3.0: version "8.3.2" resolved "https://registry.yarnpkg.com/react-textarea-autosize/-/react-textarea-autosize-8.3.2.tgz#4f9374d357b0a6f6469956726722549124a1b2db" @@ -18335,6 +18415,11 @@ require-main-filename@^2.0.0: resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== +requireindex@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/requireindex/-/requireindex-1.2.0.tgz#3463cdb22ee151902635aa6c9535d4de9c2ef1ef" + integrity sha512-L9jEkOi3ASd9PYit2cwRfyppc9NoABujTP8/5gFcbERmo5jUoAKovIC3fsF17pkTnGsrByysqX+Kxd2OTNI1ww== + requires-port@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" @@ -18665,14 +18750,6 @@ saxes@^5.0.0: dependencies: xmlchars "^2.2.0" -scheduler@^0.20.1: - version "0.20.1" - resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.20.1.tgz#da0b907e24026b01181ecbc75efdc7f27b5a000c" - integrity sha512-LKTe+2xNJBNxu/QhHvDR14wUXHRQbVY5ZOYpOGWRzhydZUqrLb2JBvLPY7cAqFmqrWuDED0Mjk7013SZiOz6Bw== - dependencies: - loose-envify "^1.1.0" - object-assign "^4.1.1" - scheduler@^0.20.2: version "0.20.2" resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.20.2.tgz#4baee39436e34aa93b4874bddcbf0fe8b8b50e91" @@ -20345,6 +20422,13 @@ tsutils@^3.17.1: dependencies: tslib "^1.8.1" +tsutils@^3.21.0: + version "3.21.0" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" + integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== + dependencies: + tslib "^1.8.1" + tty-browserify@0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6"