Explorar o código

Update `unit tests`

Signed-off-by: Mihaela Balutoiu <mbalutoiu@cloudbasesolutions.com>

fix unit testing
Mihaela Balutoiu hai 1 ano
pai
achega
350aa275ed
Modificáronse 50 ficheiros con 622 adicións e 331 borrados
  1. 1 1
      src/components/modules/DashboardModule/DashboardActivity/DashboardActivity.spec.tsx
  2. 4 2
      src/components/modules/DashboardModule/DashboardContent/DashboardContent.spec.tsx
  3. 1 1
      src/components/modules/DashboardModule/DashboardInfoCount/DashboardInfoCount.spec.tsx
  4. 1 1
      src/components/modules/DashboardModule/DashboardTopEndpoints/DashboardTopEndpoints.spec.tsx
  5. 1 1
      src/components/modules/DetailsModule/DetailsContentHeader/DetailsContentHeader.spec.tsx
  6. 45 28
      src/components/modules/DetailsModule/DetailsPageHeader/DetailsPageHeader.spec.tsx
  7. 1 1
      src/components/modules/EndpointModule/ChooseProvider/ChooseProvider.spec.tsx
  8. 1 1
      src/components/modules/EndpointModule/EndpointDetailsContent/EndpointDetailsContent.spec.tsx
  9. 19 10
      src/components/modules/MetalHubModule/MetalHubModal/MetalHubModal.spec.tsx
  10. 8 4
      src/components/modules/MetalHubModule/MetalHubServerDetailsContent/MetalHubServerDetailsContent.spec.tsx
  11. 9 5
      src/components/modules/MinionModule/MinionEndpointModal/MinionEndpointModal.spec.tsx
  12. 1 1
      src/components/modules/MinionModule/MinionPoolDetailsContent/MinionPoolDetailsContent.spec.tsx
  13. 29 16
      src/components/modules/MinionModule/MinionPoolDetailsContent/MinionPoolEvents.spec.tsx
  14. 21 13
      src/components/modules/MinionModule/MinionPoolDetailsContent/MinionPoolMachines.spec.tsx
  15. 1 1
      src/components/modules/MinionModule/MinionPoolDetailsContent/MinionPoolMainDetails.spec.tsx
  16. 9 5
      src/components/modules/MinionModule/MinionPoolModal/MinionPoolModalContent.spec.tsx
  17. 5 3
      src/components/modules/NavigationModule/NavigationMini/NavigationMini.spec.tsx
  18. 40 29
      src/components/modules/ProjectModule/ProjectDetailsContent/ProjectDetailsContent.spec.tsx
  19. 21 11
      src/components/modules/SetupModule/SetupPageLegal/SetupPageLegal.spec.tsx
  20. 1 1
      src/components/modules/TransferModule/DeploymentDetailsContent/DeploymentDetailsContent.spec.tsx
  21. 34 16
      src/components/modules/TransferModule/Executions/Executions.spec.tsx
  22. 6 4
      src/components/modules/TransferModule/MainDetails/MainDetails.spec.tsx
  23. 50 24
      src/components/modules/TransferModule/Schedule/Schedule.spec.tsx
  24. 22 10
      src/components/modules/TransferModule/ScheduleItem/ScheduleItem.spec.tsx
  25. 5 3
      src/components/modules/TransferModule/Tasks/Tasks.spec.tsx
  26. 6 4
      src/components/modules/TransferModule/TransferDetailsContent/ReplicaDetailsContent.spec.tsx
  27. 11 5
      src/components/modules/TransferModule/TransferDetailsTable/TransferDetailsTable.spec.tsx
  28. 1 1
      src/components/modules/UserModule/UserDetailsContent/UserDetailsContent.spec.tsx
  29. 1 1
      src/components/modules/WizardModule/WizardOptions/WizardOptions.spec.tsx
  30. 7 3
      src/components/ui/AutocompleteInput/AutocompleteInput.spec.tsx
  31. 7 3
      src/components/ui/DatetimePicker/DatetimePicker.spec.tsx
  32. 23 11
      src/components/ui/Dropdowns/ActionDropdown/ActionDropdown.spec.tsx
  33. 5 3
      src/components/ui/Dropdowns/AutocompleteDropdown/AutocompleteDropdown.spec.tsx
  34. 13 5
      src/components/ui/Dropdowns/Dropdown/Dropdown.spec.tsx
  35. 10 4
      src/components/ui/Dropdowns/DropdownFilter/DropdownFilter.spec.tsx
  36. 4 2
      src/components/ui/Dropdowns/DropdownFilterGroup/DropdownFilterGroup.spec.tsx
  37. 16 8
      src/components/ui/Dropdowns/DropdownLink/DropdownLink.spec.tsx
  38. 11 5
      src/components/ui/Dropdowns/NewItemDropdown/NewItemDropdown.spec.tsx
  39. 17 9
      src/components/ui/Dropdowns/NotificationDropdown/NotificationDropdown.spec.tsx
  40. 14 6
      src/components/ui/Dropdowns/UserDropdown/UserDropdown.spec.tsx
  41. 13 7
      src/components/ui/FieldInput/FieldInput.spec.tsx
  42. 13 7
      src/components/ui/Lists/FilterList/FilterList.spec.tsx
  43. 16 8
      src/components/ui/Lists/MainListFilter/MainListFilter.spec.tsx
  44. 16 8
      src/components/ui/Lists/MainMultiFilterList/MainMultiFilterList.spec.tsx
  45. 2 2
      src/components/ui/Logo/Logo.spec.tsx
  46. 4 2
      src/components/ui/PasswordValue/PasswordValue.spec.tsx
  47. 19 10
      src/components/ui/PropertiesTable/PropertiesTable.spec.tsx
  48. 4 2
      src/components/ui/SearchInput/SearchInput.spec.tsx
  49. 44 19
      src/components/ui/Stepper/Stepper.spec.tsx
  50. 9 4
      src/components/ui/Switch/Switch.spec.tsx

+ 1 - 1
src/components/modules/DashboardModule/DashboardActivity/DashboardActivity.spec.tsx

@@ -24,7 +24,7 @@ const encodedProgressImage = encodeURIComponent(
   progressImage(ThemePalette.grayscale[3], ThemePalette.primary)
 );
 
-jest.mock("react-router-dom", () => ({ Link: "a" }));
+jest.mock("react-router", () => ({ Link: "a" }));
 
 const ITEMS: NotificationItemData[] = [
   {

+ 4 - 2
src/components/modules/DashboardModule/DashboardContent/DashboardContent.spec.tsx

@@ -19,7 +19,7 @@ import TestUtils from "@tests/TestUtils";
 
 import DashboardContent from "./DashboardContent";
 
-jest.mock("react-router-dom", () => ({ Link: "div" }));
+jest.mock("react-router", () => ({ Link: "div" }));
 
 describe("DashboardContent", () => {
   let resizeWindow: (x: number, y: number) => void;
@@ -126,6 +126,8 @@ describe("DashboardContent", () => {
     expect(setStateMock).toHaveBeenCalledWith({ useMobileLayout: true });
 
     setStateMock.mockRestore();
-    resizeWindow(2400, 800);
+    act(() => {
+      resizeWindow(2400, 800);
+    });
   });
 });

+ 1 - 1
src/components/modules/DashboardModule/DashboardInfoCount/DashboardInfoCount.spec.tsx

@@ -19,7 +19,7 @@ import TestUtils from "@tests/TestUtils";
 
 import DashboardInfoCount from "./DashboardInfoCount";
 
-jest.mock("react-router-dom", () => ({ Link: "a" }));
+jest.mock("react-router", () => ({ Link: "a" }));
 
 describe("DashboardInfoCount", () => {
   const mockData = [

+ 1 - 1
src/components/modules/DashboardModule/DashboardTopEndpoints/DashboardTopEndpoints.spec.tsx

@@ -21,7 +21,7 @@ import TestUtils from "@tests/TestUtils";
 
 import DashboardTopEndpoints from "./DashboardTopEndpoints";
 
-jest.mock("react-router-dom", () => ({ Link: "a" }));
+jest.mock("react-router", () => ({ Link: "a" }));
 
 type BuildType<T extends "replica" | "migration"> = T extends "replica"
   ? TransferItem

+ 1 - 1
src/components/modules/DetailsModule/DetailsContentHeader/DetailsContentHeader.spec.tsx

@@ -20,7 +20,7 @@ import TestUtils from "@tests/TestUtils";
 
 import DetailsContentHeader from "./DetailsContentHeader";
 
-jest.mock("react-router-dom", () => ({ Link: "a" }));
+jest.mock("react-router", () => ({ Link: "a" }));
 
 describe("DetailsContentHeader", () => {
   let defaultProps: DetailsContentHeader["props"];

+ 45 - 28
src/components/modules/DetailsModule/DetailsPageHeader/DetailsPageHeader.spec.tsx

@@ -12,8 +12,7 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-import React from "react";
-import { act } from "react-dom/test-utils";
+import React, { act }  from "react";
 
 import { User } from "@src/@types/User";
 import notificationStore from "@src/stores/NotificationStore";
@@ -22,7 +21,7 @@ import TestUtils from "@tests/TestUtils";
 
 import DetailsPageHeader from "./DetailsPageHeader";
 
-jest.mock("react-router-dom", () => ({ Link: "a" }));
+jest.mock("react-router", () => ({ Link: "a" }));
 jest.mock("@src/stores/NotificationStore", () => ({
   notificationItems: [],
   loadData: jest.fn().mockResolvedValue([]),
@@ -89,18 +88,24 @@ describe("DetailsPageHeader", () => {
     expect(notificationStore.loadData).toHaveBeenCalledTimes(1);
   });
 
-  it("handles notification close by saving seen notifications", () => {
+  it("handles notification close by saving seen notifications", async () => {
     render(<DetailsPageHeader {...defaultProps} />);
-    TestUtils.select("NotificationDropdown__Icon")?.click();
+    await act(async () => {
+      TestUtils.select("NotificationDropdown__Icon")?.click();
+    });
     expect(TestUtils.select("NotificationDropdown__List")).toBeTruthy();
-    TestUtils.select("NotificationDropdown__Icon")?.click();
+    await act(async () => {
+      TestUtils.select("NotificationDropdown__Icon")?.click();
+    });
     expect(TestUtils.select("NotificationDropdown__List")).toBeFalsy();
     expect(notificationStore.saveSeen).toHaveBeenCalled();
   });
 
-  it("handles user item click for 'about'", () => {
+  it("handles user item click for 'about'", async () => {
     render(<DetailsPageHeader {...defaultProps} />);
-    TestUtils.select("UserDropdown__Icon")?.click();
+    await act(async () => {
+      TestUtils.select("UserDropdown__Icon")?.click();
+    });
     expect(TestUtils.select("UserDropdown__List")).toBeTruthy();
     expect(TestUtils.select("UserDropdown__Username")?.textContent).toBe(
       user.name
@@ -108,23 +113,29 @@ describe("DetailsPageHeader", () => {
     expect(TestUtils.select("UserDropdown__Email")?.textContent).toBe(
       user.email
     );
-    TestUtils.selectAll("UserDropdown__Label").forEach(item => {
-      if (item.textContent === "About Coriolis") {
-        item.click();
-      }
+    await act(async () => {
+      TestUtils.selectAll("UserDropdown__Label").forEach(item => {
+        if (item.textContent === "About Coriolis") {
+          item.click();
+        }
+      });
     });
     expect(defaultProps.onUserItemClick).not.toHaveBeenCalled();
     expect(TestUtils.select("AboutModal__Wrapper")).toBeTruthy();
   });
 
-  it("handles user item click for other values", () => {
+  it("handles user item click for other values", async () => {
     render(<DetailsPageHeader {...defaultProps} />);
-    TestUtils.select("UserDropdown__Icon")?.click();
+    await act(async () => {
+      TestUtils.select("UserDropdown__Icon")?.click();
+    });
     expect(TestUtils.select("UserDropdown__List")).toBeTruthy();
-    TestUtils.selectAll("UserDropdown__Label").forEach(item => {
-      if (item.textContent === "Sign Out") {
-        item.click();
-      }
+    await act(async () => {
+      TestUtils.selectAll("UserDropdown__Label").forEach(item => {
+        if (item.textContent === "Sign Out") {
+          item.click();
+        }
+      });
     });
     expect(defaultProps.onUserItemClick).toHaveBeenCalledWith({
       label: "Sign Out",
@@ -132,19 +143,25 @@ describe("DetailsPageHeader", () => {
     });
   });
 
-  it("closes the about modal", () => {
+  it("closes the about modal", async () => {
     render(<DetailsPageHeader {...defaultProps} />);
-    TestUtils.select("UserDropdown__Icon")?.click();
-    TestUtils.selectAll("UserDropdown__Label").forEach(item => {
-      if (item.textContent === "About Coriolis") {
-        item.click();
-      }
+    await act(async () => {
+      TestUtils.select("UserDropdown__Icon")?.click();
+    });
+    await act(async () => {
+      TestUtils.selectAll("UserDropdown__Label").forEach(item => {
+        if (item.textContent === "About Coriolis") {
+          item.click();
+        }
+      });
     });
     expect(TestUtils.select("AboutModal__Wrapper")).toBeTruthy();
-    document.querySelectorAll("button").forEach(item => {
-      if (item.textContent === "Close") {
-        item.click();
-      }
+    await act(async () => {
+      document.querySelectorAll("button").forEach(item => {
+        if (item.textContent === "Close") {
+          item.click();
+        }
+      });
     });
     expect(TestUtils.select("AboutModal__Wrapper")).toBeFalsy();
   });

+ 1 - 1
src/components/modules/EndpointModule/ChooseProvider/ChooseProvider.spec.tsx

@@ -46,7 +46,7 @@ const mockDataTransfer = (files: any[]) => ({
   },
 });
 
-jest.mock("react-router-dom", () => ({ Link: "a" }));
+jest.mock("react-router", () => ({ Link: "a" }));
 
 jest.mock("@src/stores/NotificationStore", () => ({
   alert: jest.fn(),

+ 1 - 1
src/components/modules/EndpointModule/EndpointDetailsContent/EndpointDetailsContent.spec.tsx

@@ -32,7 +32,7 @@ jest.mock("@src/utils/Config", () => ({
   },
 }));
 
-jest.mock("react-router-dom", () => ({
+jest.mock("react-router", () => ({
   Link: "div",
 }));
 

+ 19 - 10
src/components/modules/MetalHubModule/MetalHubModal/MetalHubModal.spec.tsx

@@ -12,7 +12,7 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-import React from "react";
+import React, { act } from "react";
 
 import metalHubStore from "@src/stores/MetalHubStore";
 import { fireEvent, render, waitFor } from "@testing-library/react";
@@ -74,14 +74,18 @@ describe("MetalHubModal", () => {
     );
   });
 
-  it("renders validation error", () => {
-    metalHubStore.validationError = ["Validation error", "Validation error 2"];
+  it("renders validation error", async () => {
+    await act(async () => {
+      metalHubStore.validationError = ["Validation error", "Validation error 2"];
+    });
     const { getByText } = render(
       <MetalHubModal {...defaultProps} server={{ ...METALHUB_SERVER_MOCK }} />
     );
     expect(getByText("Validation error")).toBeTruthy();
     expect(getByText("Validation error 2")).toBeTruthy();
-    metalHubStore.validationError = [];
+    await act(async () => {
+      metalHubStore.validationError = [];
+    });
   });
 
   it("triggers submit on enter key", async () => {
@@ -89,18 +93,22 @@ describe("MetalHubModal", () => {
       <MetalHubModal {...defaultProps} server={{ ...METALHUB_SERVER_MOCK }} />
     );
     const input = document.querySelector("input")!;
-    fireEvent.keyDown(input, { key: "Enter", code: "Enter" });
+    await act(async () => {
+      fireEvent.keyDown(input, { key: "Enter", code: "Enter" });
+    });
     await waitFor(() => {
       expect(metalHubStoreSpies.patchServer).toHaveBeenCalledTimes(1);
     });
     expect(metalHubStoreSpies.validateServer).toHaveBeenCalledTimes(1);
   });
 
-  it("highlights invalid fields", () => {
+  it("highlights invalid fields", async () => {
     const { getByText, getAllByText } = render(
       <MetalHubModal {...defaultProps} />
     );
-    fireEvent.click(getByText("Validate and save"));
+    await act(async () => {
+      fireEvent.click(getByText("Validate and save"));
+    });
     expect(getAllByText("Required field").length).toBeGreaterThan(0);
   });
 
@@ -108,13 +116,14 @@ describe("MetalHubModal", () => {
     const { getByText } = render(<MetalHubModal {...defaultProps} />);
     const getInput = (label: string): HTMLInputElement =>
       getByText(label).parentElement!.parentElement!.querySelector("input")!;
-
     fireEvent.change(getInput("Host"), {
       target: { value: "api.example.com" },
     });
     fireEvent.change(getInput("Port"), { target: { value: "5566" } });
-    fireEvent.click(getByText("Validate and save"));
-    await waitFor(() => {
+    await act(async () => {
+      fireEvent.click(getByText("Validate and save"));
+    });
+    await act(async () => {
       expect(metalHubStoreSpies.addServer).toHaveBeenCalledWith(
         "https://api.example.com:5566/api/v1"
       );

+ 8 - 4
src/components/modules/MetalHubModule/MetalHubServerDetailsContent/MetalHubServerDetailsContent.spec.tsx

@@ -12,7 +12,7 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-import React from "react";
+import React, { act } from "react";
 
 import DateUtils from "@src/utils/DateUtils";
 import { render } from "@testing-library/react";
@@ -78,17 +78,21 @@ describe("MetalHubServerDetailsContent", () => {
     ).toBeTruthy();
   });
 
-  it("handles row click", () => {
+  it("handles row click", async () => {
     const { getAllByTestId } = render(
       <MetalHubServerDetailsContent {...defaultProps} />
     );
     const row = TestUtils.select("TransferDetailsTable__Row-")!;
     expect(row).toBeTruthy();
     expect(getAllByTestId("Arrow")[0].textContent).toBe("Orientation: down");
-    row.click();
+    await act(async () => {
+      row.click();
+    });
     expect(getAllByTestId("Arrow")[0].textContent).toBe("Orientation: up");
 
-    row.click();
+    await act(async () => {
+      row.click();
+    });
     expect(getAllByTestId("Arrow")[0].textContent).toBe("Orientation: down");
   });
 

+ 9 - 5
src/components/modules/MinionModule/MinionEndpointModal/MinionEndpointModal.spec.tsx

@@ -12,7 +12,7 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-import React from "react";
+import React, { act } from "react";
 
 import { render } from "@testing-library/react";
 import {
@@ -32,7 +32,7 @@ jest.mock("@src/components/modules/EndpointModule/EndpointLogos", () => ({
 }));
 
 jest.mock("react-transition-group", () => ({
-  CSSTransitionGroup: (props: any) => <div>{props.children}</div>,
+  CSSTransition: (props: any) => <div>{props.children}</div>,
 }));
 
 describe("MinionEndpointModal", () => {
@@ -72,10 +72,14 @@ describe("MinionEndpointModal", () => {
     ).toContain("Please create a Coriolis Endpoint");
   });
 
-  it("selects an endpoint", () => {
+  it("selects an endpoint", async () => {
     const { getByText } = render(<MinionEndpointModal {...defaultProps} />);
-    TestUtils.select("DropdownButton__Wrapper")?.click();
-    TestUtils.select("Dropdown__ListItem-")?.click();
+    await act(async () => {
+      TestUtils.select("DropdownButton__Wrapper")?.click();
+    });
+    await act(async () => {
+      TestUtils.select("Dropdown__ListItem-")?.click();
+    });
     getByText("Next").click();
     expect(defaultProps.onSelectEndpoint).toHaveBeenCalledWith(
       VMWARE_ENDPOINT_MOCK,

+ 1 - 1
src/components/modules/MinionModule/MinionPoolDetailsContent/MinionPoolDetailsContent.spec.tsx

@@ -22,7 +22,7 @@ import TestUtils from "@tests/TestUtils";
 
 import MinionPoolDetailsContent from "./MinionPoolDetailsContent";
 
-jest.mock("react-router-dom", () => ({ Link: "a" }));
+jest.mock("react-router", () => ({ Link: "a" }));
 jest.mock("@src/components/modules/EndpointModule/EndpointLogos", () => ({
   __esModule: true,
   default: (props: any) => (

+ 29 - 16
src/components/modules/MinionModule/MinionPoolDetailsContent/MinionPoolEvents.spec.tsx

@@ -12,7 +12,7 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-import React from "react";
+import React, { act } from "react";
 
 import { render } from "@testing-library/react";
 import { MINION_POOL_DETAILS_MOCK } from "@tests/mocks/MinionPoolMock";
@@ -49,7 +49,7 @@ describe("MinionPoolEvents", () => {
     ${"INFO Event Level"} | ${"DEBUG Event Level"}
     ${"INFO Event Level"} | ${"ERROR Event Level"}
     ${"Descending Order"} | ${"Ascending Order"}
-  `("filters by $fromLabel to $toLabel", ({ fromLabel, toLabel }) => {
+  `("filters by $fromLabel to $toLabel", async ({ fromLabel, toLabel }) => {
     render(<MinionPoolEvents {...defaultProps} />);
     let filterDropdown: HTMLElement | null = null;
     TestUtils.selectAll("DropdownLink__Label").forEach(element => {
@@ -58,7 +58,9 @@ describe("MinionPoolEvents", () => {
       }
     });
     expect(filterDropdown).toBeTruthy();
-    filterDropdown!.click();
+    await act(async () => {
+      filterDropdown!.click();
+    });
     let listItem: HTMLElement | null = null;
     TestUtils.selectAll("DropdownLink__ListItem-").forEach(element => {
       if (element.textContent === toLabel) {
@@ -66,7 +68,10 @@ describe("MinionPoolEvents", () => {
       }
     });
     expect(listItem).toBeTruthy();
-    listItem!.click();
+
+    await act(async () => {
+      listItem!.click();
+    });
 
     TestUtils.selectAll("DropdownLink__Label").forEach(element => {
       if (element.textContent === toLabel) {
@@ -77,7 +82,7 @@ describe("MinionPoolEvents", () => {
   });
 
   describe("Pagination", () => {
-    const showAllEvents = () => {
+    const showAllEvents = async () => {
       let showAllEvents: HTMLElement | null = null;
       TestUtils.selectAll("DropdownLink__Label").forEach(element => {
         if (element.textContent === "Events") {
@@ -85,7 +90,9 @@ describe("MinionPoolEvents", () => {
         }
       });
       expect(showAllEvents).toBeTruthy();
-      showAllEvents!.click();
+      await act(async () => {
+        showAllEvents!.click();
+      });
       let listItem: HTMLElement | null = null;
       TestUtils.selectAll("DropdownLink__ListItem-").forEach(element => {
         if (element.textContent === "Events & Progress Updates") {
@@ -93,34 +100,37 @@ describe("MinionPoolEvents", () => {
         }
       });
       expect(listItem).toBeTruthy();
-      listItem!.click();
+      await act(async () => {
+        listItem!.click();
+      });
     };
 
-    it("has pagination", () => {
+    it("has pagination", async () => {
       render(<MinionPoolEvents {...defaultProps} />);
 
       // pagination is not visible for 1 event
       expect(TestUtils.select("Pagination__Wrapper")!).toBeFalsy();
 
-      showAllEvents();
+      await showAllEvents();
 
       // pagination is visible for more than 1 event
       expect(TestUtils.select("Pagination__Wrapper")!).toBeTruthy();
     });
 
-    it("goes to next page and back", () => {
+    it("goes to next page and back", async () => {
       render(<MinionPoolEvents {...defaultProps} />);
 
-      showAllEvents();
+      await showAllEvents();
 
       expect(
         TestUtils.select("Pagination__PagePrevious")!.hasAttribute("disabled")
       ).toBeTruthy();
-      expect(TestUtils.select("Pagination__PageNumber")!.textContent).toBe(
-        "1 of 3"
-      );
+      expect(TestUtils.select("Pagination__PageNumber")!.textContent).toBe("1 of 3");
+
+      await act(async () => {
+        TestUtils.select("Pagination__PageNext")!.click();
+      });
 
-      TestUtils.select("Pagination__PageNext")!.click();
       expect(
         TestUtils.select("Pagination__PagePrevious")!.hasAttribute("disabled")
       ).toBeFalsy();
@@ -128,7 +138,10 @@ describe("MinionPoolEvents", () => {
         "2 of 3"
       );
 
-      TestUtils.select("Pagination__PagePrevious")!.click();
+      await act(async () => {
+        TestUtils.select("Pagination__PagePrevious")!.click();
+      });
+    
       expect(TestUtils.select("Pagination__PageNumber")!.textContent).toBe(
         "1 of 3"
       );

+ 21 - 13
src/components/modules/MinionModule/MinionPoolDetailsContent/MinionPoolMachines.spec.tsx

@@ -12,7 +12,7 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-import React from "react";
+import React, { act } from "react";
 
 import { render } from "@testing-library/react";
 import { MINION_POOL_MOCK } from "@tests/mocks/MinionPoolMock";
@@ -21,7 +21,7 @@ import TestUtils from "@tests/TestUtils";
 
 import MinionPoolMachines from "./MinionPoolMachines";
 
-jest.mock("react-router-dom", () => ({ Link: "a" }));
+jest.mock("react-router", () => ({ Link: "a" }));
 
 describe("MinionPoolMachines", () => {
   let defaultProps: MinionPoolMachines["props"];
@@ -34,7 +34,7 @@ describe("MinionPoolMachines", () => {
     };
   });
 
-  const filterBy = (fromLabel: string, toLabel: string) => {
+  const filterBy = async (fromLabel: string, toLabel: string) => {
     let filterDropdown: HTMLElement | null = null;
     TestUtils.selectAll("DropdownLink__Label").forEach(element => {
       if (element.textContent === fromLabel) {
@@ -43,8 +43,10 @@ describe("MinionPoolMachines", () => {
     });
     expect(filterDropdown).toBeTruthy();
 
-    filterDropdown!.click();
-
+    await act(async () => {
+      filterDropdown!.click();
+    });
+  
     let filterItem: HTMLElement | null = null;
     TestUtils.selectAll("DropdownLink__ListItem-").forEach(element => {
       if (element.textContent === toLabel) {
@@ -52,7 +54,9 @@ describe("MinionPoolMachines", () => {
       }
     });
     expect(filterItem).toBeTruthy();
-    filterItem!.click();
+    await act(async () => {
+      filterItem!.click();
+    });
   };
 
   it("renders without crashing", () => {
@@ -65,14 +69,14 @@ describe("MinionPoolMachines", () => {
     ).toBeTruthy();
   });
 
-  it("filters correctly", () => {
+  it("filters correctly", async () => {
     render(<MinionPoolMachines {...defaultProps} />);
-    filterBy("All", "Allocated");
+    await filterBy("All", "Allocated");
     expect(
       TestUtils.selectAll("MinionPoolMachines__MachineWrapper").length
     ).toBe(1);
-
-    filterBy("Allocated", "Not Allocated");
+  
+    await filterBy("Allocated", "Not Allocated");
     expect(
       TestUtils.selectAll("MinionPoolMachines__MachineWrapper").length
     ).toBe(0);
@@ -88,7 +92,7 @@ describe("MinionPoolMachines", () => {
     expect(TestUtils.select("MinionPoolMachines__NoMachines")).toBeTruthy();
   });
 
-  it("handles row click", () => {
+  it("handles row click", async () => {
     render(<MinionPoolMachines {...defaultProps} />);
     const arrow = TestUtils.select(
       "Arrow__Wrapper",
@@ -97,10 +101,14 @@ describe("MinionPoolMachines", () => {
     expect(arrow).toBeTruthy();
     expect(arrow!.attributes.getNamedItem("orientation")!.value).toBe("down");
 
-    TestUtils.select("MinionPoolMachines__Row-")!.click();
+    await act(async () => {
+      TestUtils.select("MinionPoolMachines__Row-")!.click();
+    });
     expect(arrow!.attributes.getNamedItem("orientation")!.value).toBe("up");
 
-    TestUtils.select("MinionPoolMachines__Row-")!.click();
+    await act(async () => {
+      TestUtils.select("MinionPoolMachines__Row-")!.click();
+    });
     expect(arrow!.attributes.getNamedItem("orientation")!.value).toBe("down");
   });
 });

+ 1 - 1
src/components/modules/MinionModule/MinionPoolDetailsContent/MinionPoolMainDetails.spec.tsx

@@ -21,7 +21,7 @@ import { DEPLOYMENT_MOCK, TRANSFER_MOCK } from "@tests/mocks/TransferMock";
 
 import MinionPoolMainDetails from "./MinionPoolMainDetails";
 
-jest.mock("react-router-dom", () => ({ Link: "a" }));
+jest.mock("react-router", () => ({ Link: "a" }));
 jest.mock("@src/components/modules/EndpointModule/EndpointLogos", () => ({
   __esModule: true,
   default: (props: any) => (

+ 9 - 5
src/components/modules/MinionModule/MinionPoolModal/MinionPoolModalContent.spec.tsx

@@ -12,7 +12,7 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-import React from "react";
+import React, { act } from "react";
 
 import { fireEvent, render } from "@testing-library/react";
 import { OPENSTACK_ENDPOINT_MOCK } from "@tests/mocks/EndpointsMock";
@@ -86,18 +86,22 @@ describe("MinionPoolModalContent", () => {
     expect(getByText("Environment Options")).toBeTruthy();
   });
 
-  it("calls resize on simple / advanced toggle", () => {
+  it("calls resize on simple / advanced toggle", async () => {
     const { getByText } = render(<MinionPoolModalContent {...defaultProps} />);
-    getByText("Advanced").click();
+    await act(async () => {
+      getByText("Advanced").click();
+    });
     expect(defaultProps.onResizeUpdate).toHaveBeenCalled();
   });
 
-  it("filters non required fields", () => {
+  it("filters non required fields", async () => {
     const { getByText } = render(<MinionPoolModalContent {...defaultProps} />);
     expect(TestUtils.selectAll("FieldInput__LabelText")[1].textContent).toBe(
       "Required Env Option"
     );
-    getByText("Advanced").click();
+    await act(async () => {
+      getByText("Advanced").click();
+    });
     expect(TestUtils.selectAll("FieldInput__LabelText")[1].textContent).toBe(
       "Env Option"
     );

+ 5 - 3
src/components/modules/NavigationModule/NavigationMini/NavigationMini.spec.tsx

@@ -12,14 +12,14 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-import React from "react";
+import React, { act } from "react";
 
 import { render } from "@testing-library/react";
 
 import NavigationMini from "./";
 import TestUtils from "@tests/TestUtils";
 
-jest.mock("react-router-dom", () => ({ Link: "a" }));
+jest.mock("react-router", () => ({ Link: "a" }));
 jest.mock("@src/components/modules/NavigationModule/Navigation", () => ({
   __esModule: true,
   default: (props: any) => (
@@ -36,7 +36,9 @@ describe("NavigationMini", () => {
   it("toggles the menu", () => {
     const { getByTestId } = render(<NavigationMini />);
     expect(getByTestId("navigation").textContent).toBe("open: false");
-    TestUtils.select("NavigationMini__MenuImage")!.click();
+    act(() => {
+      TestUtils.select("NavigationMini__MenuImage")!.click();
+    });
     expect(getByTestId("navigation").textContent).toBe("open: true");
   });
 });

+ 40 - 29
src/components/modules/ProjectModule/ProjectDetailsContent/ProjectDetailsContent.spec.tsx

@@ -12,7 +12,7 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-import React from "react";
+import React, {act} from "react";
 
 import { Project, RoleAssignment } from "@src/@types/Project";
 import { render } from "@testing-library/react";
@@ -21,7 +21,7 @@ import ProjectDetailsContent from "./";
 import { User } from "@src/@types/User";
 import TestUtils from "@tests/TestUtils";
 
-jest.mock("react-router-dom", () => ({ Link: "a" }));
+jest.mock("react-router", () => ({ Link: "a" }));
 
 const PROJECT: Project = {
   id: "project-id",
@@ -72,9 +72,9 @@ describe("ProjectDetailsContent", () => {
   });
 
   describe("user actions", () => {
-    const openActionsDropdown = () => {
+    const openActionsDropdown = async () => {
       const dropdowns = TestUtils.selectAll("DropdownLink__LinkButton");
-      let actionsDropdown;
+      let actionsDropdown: HTMLElement | undefined;
 
       for (const dropdown of dropdowns) {
         if (dropdown.textContent?.includes("Actions")) {
@@ -82,14 +82,15 @@ describe("ProjectDetailsContent", () => {
           break;
         }
       }
-
       expect(actionsDropdown).toBeTruthy();
-      actionsDropdown?.click();
+      await act(async () => {
+        actionsDropdown?.click();
+      });
     };
 
-    const clickAction = (action: string) => {
+    const clickAction = async (action: string) => {
       const items = TestUtils.selectAll("DropdownLink__ListItem-");
-      let actionItem;
+      let actionItem: HTMLElement | undefined;
 
       for (const item of items) {
         if (item.textContent?.includes(action)) {
@@ -99,38 +100,44 @@ describe("ProjectDetailsContent", () => {
       }
 
       expect(actionItem).toBeTruthy();
-      actionItem?.click();
+      await act(async () => {
+        actionItem?.click();
+      });
     };
 
-    it("removes user", () => {
+    it("removes user", async () => {
       render(<ProjectDetailsContent {...defaultProps} />);
 
-      openActionsDropdown();
-      clickAction("Remove");
+      await openActionsDropdown();
+      await clickAction("Remove");
 
       expect(TestUtils.select("AlertModal__Message")).toBeTruthy();
-      TestUtils.select("AlertModal__Buttons")
-        ?.querySelectorAll("button")[1]
-        .click();
+      await act(async () => {
+        TestUtils.select("AlertModal__Buttons")
+          ?.querySelectorAll("button")[1]
+          .click();
+      });
 
       expect(defaultProps.onRemoveUser).toBeCalled();
     });
 
-    it("cancels removing user", () => {
+    it("cancels removing user", async () => {
       render(<ProjectDetailsContent {...defaultProps} />);
 
-      openActionsDropdown();
-      clickAction("Remove");
+      await openActionsDropdown();
+      await clickAction("Remove");
 
       expect(TestUtils.select("AlertModal__Message")).toBeTruthy();
-      TestUtils.select("AlertModal__Buttons")
-        ?.querySelectorAll("button")[0]
-        .click();
+      await act(async () => {
+        TestUtils.select("AlertModal__Buttons")
+          ?.querySelectorAll("button")[0]
+          .click();
+      });
 
       expect(defaultProps.onRemoveUser).not.toBeCalled();
     });
 
-    it("enables user", () => {
+    it("enables user", async () => {
       render(
         <ProjectDetailsContent
           {...defaultProps}
@@ -138,8 +145,8 @@ describe("ProjectDetailsContent", () => {
         />
       );
 
-      openActionsDropdown();
-      clickAction("Enable");
+      await openActionsDropdown();
+      await clickAction("Enable");
 
       expect(defaultProps.onEnableUser).toBeCalled();
     });
@@ -160,10 +167,10 @@ describe("ProjectDetailsContent", () => {
     ).toBeTruthy();
   });
 
-  it("changes user role", () => {
+  it("changes user role", async () => {
     render(<ProjectDetailsContent {...defaultProps} />);
     const dropdowns = TestUtils.selectAll("DropdownLink__LinkButton");
-    let roleDropdown;
+    let roleDropdown: HTMLElement | undefined;
 
     for (const dropdown of dropdowns) {
       if (dropdown.textContent?.includes(ROLE_ASSIGNMENT.role.name)) {
@@ -173,10 +180,12 @@ describe("ProjectDetailsContent", () => {
     }
 
     expect(roleDropdown).toBeTruthy();
-    roleDropdown?.click();
+    await act(async () => {
+      roleDropdown?.click();
+    });
 
     const items = TestUtils.selectAll("DropdownLink__ListItem-");
-    let roleItem;
+    let roleItem: HTMLElement | undefined ;
 
     for (const item of items) {
       if (item.textContent?.includes(ROLE_ASSIGNMENT.role.name)) {
@@ -186,7 +195,9 @@ describe("ProjectDetailsContent", () => {
     }
 
     expect(roleItem).toBeTruthy();
-    roleItem?.click();
+    await act(async () => {
+      roleItem?.click();
+    });
 
     expect(defaultProps.onUserRoleChange).toBeCalledWith(
       USER,

+ 21 - 11
src/components/modules/SetupModule/SetupPageLegal/SetupPageLegal.spec.tsx

@@ -12,7 +12,7 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-import React from "react";
+import React, { act } from "react";
 
 import { render } from "@testing-library/react";
 import TestUtils from "@tests/TestUtils";
@@ -98,7 +98,7 @@ describe("SetupPageLegal", () => {
     );
   });
 
-  it("fires legal agreement change event", () => {
+  it("fires legal agreement change event", async () => {
     render(<SetupPageLegal {...defaultProps} />);
     const findCheckboxByText = (text: string) =>
       Array.from(TestUtils.selectAll("Checkbox__Wrapper")).find(el =>
@@ -107,14 +107,16 @@ describe("SetupPageLegal", () => {
 
     const privacyCheckbox = findCheckboxByText("Privacy Policy");
     expect(privacyCheckbox).toBeTruthy();
-
-    privacyCheckbox.click();
+    await act(async () => {
+      privacyCheckbox.click();
+    });
     expect(defaultProps.onLegalChange).toHaveBeenCalledWith(false);
 
     const eulaCheckbox = findCheckboxByText("EULA");
     expect(eulaCheckbox).toBeTruthy();
-
-    eulaCheckbox.click();
+    await act(async () => {
+      eulaCheckbox.click();
+    });
     expect(defaultProps.onLegalChange).toHaveBeenCalledWith(true);
 
     const findLabelByText = (text: string) =>
@@ -124,12 +126,16 @@ describe("SetupPageLegal", () => {
 
     const privacyLabel = findLabelByText("Privacy Policy");
     expect(privacyLabel).toBeTruthy();
-    privacyLabel.click();
+    await act(async () => {
+      privacyLabel.click();
+    });
     expect(defaultProps.onLegalChange).toHaveBeenCalledWith(false);
 
     const eulaLabel = findLabelByText("EULA");
     expect(eulaLabel).toBeTruthy();
-    eulaLabel.click();
+    await act(async () => {
+      eulaLabel.click();
+    });
     expect(defaultProps.onLegalChange).toHaveBeenCalledWith(false);
   });
 
@@ -139,7 +145,7 @@ describe("SetupPageLegal", () => {
     ${"Destination"} | ${3}      | ${"aws"}
   `(
     "fires $platformType platform change event",
-    ({ platformType, itemIndex, expectedProvider }) => {
+    async ({ platformType, itemIndex, expectedProvider }) => {
       render(<SetupPageLegal {...defaultProps} />);
       const platformDropdown = Array.from(
         TestUtils.selectAll("Dropdown__Wrapper")
@@ -150,8 +156,12 @@ describe("SetupPageLegal", () => {
       )!;
 
       expect(platformDropdown).toBeTruthy();
-      TestUtils.select("DropdownButton__Wrapper", platformDropdown)!.click();
-      TestUtils.selectAll("Dropdown__ListItem-")[itemIndex].click();
+      await act(async () => {
+        TestUtils.select("DropdownButton__Wrapper", platformDropdown)!.click();
+      });
+      await act(async () => {
+        TestUtils.selectAll("Dropdown__ListItem-")[itemIndex].click();
+      });
 
       expect(defaultProps.onCustomerInfoChange).toHaveBeenCalledWith(
         `${platformType.toLowerCase()}Platform`,

+ 1 - 1
src/components/modules/TransferModule/DeploymentDetailsContent/DeploymentDetailsContent.spec.tsx

@@ -31,7 +31,7 @@ jest.mock("@src/components/modules/EndpointModule/EndpointLogos", () => ({
   __esModule: true,
   default: (props: any) => <div>{props.endpoint}</div>,
 }));
-jest.mock("react-router-dom", () => ({ Link: "a" }));
+jest.mock("react-router", () => ({ Link: "a" }));
 
 describe("DeploymentDetailsContent", () => {
   let defaultProps: DeploymentDetailsContent["props"];

+ 34 - 16
src/components/modules/TransferModule/Executions/Executions.spec.tsx

@@ -12,7 +12,7 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-import React from "react";
+import React, { act } from "react";
 
 import { render } from "@testing-library/react";
 import {
@@ -90,7 +90,7 @@ describe("Executions", () => {
     expect(defaultProps.onChange).not.toHaveBeenCalled();
   });
 
-  it("handles previous executions", () => {
+  it("handles previous executions", async () => {
     const { rerender } = render(
       <Executions
         {...defaultProps}
@@ -105,11 +105,15 @@ describe("Executions", () => {
         "Arrow__Wrapper",
         TestUtils.select("Timeline__Wrapper")!
       )[0];
-    previousArrow().click();
+    await act(async () => {
+      previousArrow().click();
+    });
     expect(defaultProps.onChange).toHaveBeenLastCalledWith(EXECUTION_MOCK.id);
 
     rerender(<Executions {...defaultProps} />);
-    previousArrow().click();
+    await act(async () => {
+      previousArrow().click();
+    });
     expect(defaultProps.onChange).toHaveBeenLastCalledWith(EXECUTION_MOCK.id);
   });
 
@@ -119,7 +123,7 @@ describe("Executions", () => {
     expect(defaultProps.onChange).not.toHaveBeenCalled();
   });
 
-  it("handles next executions", () => {
+  it("handles next executions", async () => {
     render(
       <Executions
         {...defaultProps}
@@ -133,7 +137,9 @@ describe("Executions", () => {
       "Arrow__Wrapper",
       TestUtils.select("Timeline__Wrapper")!
     )[1];
-    nextArrow.click();
+    await act(async () => {
+      nextArrow.click();
+    });
     expect(defaultProps.onChange).toHaveBeenLastCalledWith("new-id");
 
     const previousArrow = () =>
@@ -141,9 +147,13 @@ describe("Executions", () => {
         "Arrow__Wrapper",
         TestUtils.select("Timeline__Wrapper")!
       )[0];
-    previousArrow().click();
+    await act(async () => {
+      previousArrow().click();
+    });
 
-    nextArrow.click();
+    await act(async () => {
+      nextArrow.click();
+    });
     expect(defaultProps.onChange).toHaveBeenLastCalledWith("new-id");
   });
 
@@ -153,7 +163,7 @@ describe("Executions", () => {
     expect(defaultProps.onChange).not.toHaveBeenCalled();
   });
 
-  it("handles timeline item click", () => {
+  it("handles timeline item click", async () => {
     render(
       <Executions
         {...defaultProps}
@@ -165,11 +175,13 @@ describe("Executions", () => {
     );
     const timelineItem = TestUtils.select("Timeline__Item-");
     expect(timelineItem).toBeTruthy();
-    timelineItem!.click();
+    await act(async () => {
+      timelineItem!.click();
+    });
     expect(defaultProps.onChange).toHaveBeenLastCalledWith(EXECUTION_MOCK.id);
   });
 
-  it("handles cancel execution click", () => {
+  it("handles cancel execution click", async () => {
     const newExecution = { ...EXECUTION_MOCK, id: "new-id", status: "RUNNING" };
     render(
       <Executions
@@ -181,13 +193,15 @@ describe("Executions", () => {
       document.querySelectorAll("button")
     ).find(el => el.textContent === "Cancel Execution");
     expect(cancelExecutionButton).toBeTruthy();
-    cancelExecutionButton!.click();
+    await act(async () => {
+      cancelExecutionButton!.click();
+    });
     expect(defaultProps.onCancelExecutionClick).toHaveBeenCalledWith(
       newExecution
     );
   });
 
-  it("force cancels execution", () => {
+  it("force cancels execution", async () => {
     const newExecution = {
       ...EXECUTION_MOCK,
       id: "new-id",
@@ -203,7 +217,9 @@ describe("Executions", () => {
       document.querySelectorAll("button")
     ).find(el => el.textContent === "Force Cancel Execution");
     expect(cancelExecutionButton).toBeTruthy();
-    cancelExecutionButton!.click();
+    await act(async () => {
+      cancelExecutionButton!.click();
+    });
     expect(defaultProps.onCancelExecutionClick).toHaveBeenCalledWith(
       newExecution,
       true
@@ -215,7 +231,7 @@ describe("Executions", () => {
     expect(TestUtils.select("Executions__LoadingWrapper")).toBeTruthy();
   });
 
-  it("deletes execution", () => {
+  it("deletes execution", async () => {
     const deleteExecution = jest.fn();
     render(
       <Executions {...defaultProps} onDeleteExecutionClick={deleteExecution} />
@@ -224,7 +240,9 @@ describe("Executions", () => {
       document.querySelectorAll("button")
     ).find(el => el.textContent === "Delete Execution");
     expect(deleteExecutionButton).toBeTruthy();
-    deleteExecutionButton!.click();
+    await act(async () => {
+      deleteExecutionButton!.click();
+    });
     expect(deleteExecution).toHaveBeenCalledWith(EXECUTION_MOCK);
   });
 });

+ 6 - 4
src/components/modules/TransferModule/MainDetails/MainDetails.spec.tsx

@@ -12,7 +12,7 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-import React from "react";
+import React, { act } from "react";
 
 import { render } from "@testing-library/react";
 import {
@@ -31,7 +31,7 @@ jest.mock("@src/components/modules/EndpointModule/EndpointLogos", () => ({
   __esModule: true,
   default: (props: any) => <div>{props.endpoint}</div>,
 }));
-jest.mock("react-router-dom", () => ({ Link: "a" }));
+jest.mock("react-router", () => ({ Link: "a" }));
 
 describe("MainDetails", () => {
   let defaultProps: MainDetails["props"];
@@ -91,13 +91,15 @@ describe("MainDetails", () => {
     ).toBeTruthy();
   });
 
-  it("shows password", () => {
+  it("shows password", async () => {
     const { getByText } = render(<MainDetails {...defaultProps} />);
     const passwordEl = TestUtils.select("PasswordValue__Wrapper")!;
     expect(passwordEl).toBeTruthy();
     expect(passwordEl.textContent).toBe("•••••••••");
 
-    passwordEl.click();
+    await act(async () => {
+      passwordEl.click();
+    });
     expect(
       getByText(TRANSFER_MOCK.destination_environment.password)
     ).toBeTruthy();

+ 50 - 24
src/components/modules/TransferModule/Schedule/Schedule.spec.tsx

@@ -13,7 +13,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 import { DateTime } from "luxon";
-import React from "react";
+import React, { act } from "react";
 
 import DateUtils from "@src/utils/DateUtils";
 import { render } from "@testing-library/react";
@@ -49,43 +49,51 @@ describe("Schedule", () => {
     );
   });
 
-  it("deletes a schedule", () => {
+  it("deletes a schedule", async () => {
     render(
       <Schedule
         {...defaultProps}
         schedules={[{ ...SCHEDULE_MOCK, enabled: false }]}
       />
     );
-    TestUtils.select("ScheduleItem__DeleteButton-")?.click();
+    await act(async () => {
+      TestUtils.select("ScheduleItem__DeleteButton-")?.click();
+    });
     expect(TestUtils.select("AlertModal__Message-")?.textContent).toContain(
       "delete this schedule?"
     );
     const modal = TestUtils.select("AlertModal__Wrapper-")!;
-    Array.from(modal.querySelectorAll("button"))
-      .find(b => b.textContent === "Yes")
-      ?.click();
+    await act(async () => {
+      Array.from(modal.querySelectorAll("button"))
+        .find(b => b.textContent === "Yes")
+        ?.click();
+    });
     expect(defaultProps.onRemove).toHaveBeenCalledWith(SCHEDULE_MOCK.id);
   });
 
-  it("dismisses the delete modal", () => {
+  it("dismisses the delete modal", async () => {
     render(
       <Schedule
         {...defaultProps}
         schedules={[{ ...SCHEDULE_MOCK, enabled: false }]}
       />
     );
-    TestUtils.select("ScheduleItem__DeleteButton-")?.click();
+    await act(async () => {
+      TestUtils.select("ScheduleItem__DeleteButton-")?.click();
+    });
     expect(TestUtils.select("AlertModal__Message-")?.textContent).toContain(
       "delete this schedule?"
     );
     const modal = TestUtils.select("AlertModal__Wrapper-")!;
-    Array.from(modal.querySelectorAll("button"))
-      .find(b => b.textContent === "No")
-      ?.click();
+    await act(async () => {
+      Array.from(modal.querySelectorAll("button"))
+        .find(b => b.textContent === "No")
+        ?.click();
+    });
     expect(defaultProps.onRemove).not.toHaveBeenCalled();
   });
 
-  it("changes execution options", () => {
+  it("changes execution options", async () => {
     render(
       <Schedule
         {...defaultProps}
@@ -95,21 +103,27 @@ describe("Schedule", () => {
     const optionsButton = Array.from(document.querySelectorAll("button")).find(
       el => el.textContent === "•••"
     );
-    optionsButton?.click();
+    await act(() => {
+      optionsButton?.click();
+    });
     expect(TestUtils.select("Modal__Title-")?.textContent).toBe(
       "Execution options"
     );
     const modal = TestUtils.select("TransferExecutionOptions__Wrapper-")!;
-    TestUtils.select("Switch__InputWrapper-", modal)?.click();
+    await act(async () => {
+      TestUtils.select("Switch__InputWrapper-", modal)?.click();
+    });
     const yesButton = Array.from(modal.querySelectorAll("button")).find(
       el => el.textContent === "Save"
     );
     expect(yesButton).toBeTruthy();
-    yesButton!.click();
+    await act(async () => {
+      yesButton!.click();
+    });
     expect(defaultProps.onChange).toHaveBeenCalled();
   });
 
-  it("dismisses the execution options modal", () => {
+  it("dismisses the execution options modal", async () => {
     render(
       <Schedule
         {...defaultProps}
@@ -119,7 +133,9 @@ describe("Schedule", () => {
     const optionsButton = Array.from(document.querySelectorAll("button")).find(
       el => el.textContent === "•••"
     );
-    optionsButton?.click();
+    await act(() => {
+      optionsButton?.click();
+    });
     expect(TestUtils.select("Modal__Title-")?.textContent).toBe(
       "Execution options"
     );
@@ -128,7 +144,9 @@ describe("Schedule", () => {
       el => el.textContent === "Cancel"
     );
     expect(noButton).toBeTruthy();
-    noButton!.click();
+    await act(async () => {
+      noButton!.click();
+    });
     expect(defaultProps.onChange).not.toHaveBeenCalled();
   });
 
@@ -155,7 +173,7 @@ describe("Schedule", () => {
     expect(TestUtils.select("Schedule__LoadingWrapper")).toBeTruthy();
   });
 
-  it("changes schedule", () => {
+  it("changes schedule", async () => {
     render(
       <Schedule
         {...defaultProps}
@@ -164,12 +182,16 @@ describe("Schedule", () => {
     );
     const monthDropdown = TestUtils.select("DropdownButton__Wrapper-")!;
     expect(monthDropdown).toBeTruthy();
-    monthDropdown.click();
+    await act(async () => {
+      monthDropdown.click();
+    });
     const february = Array.from(
       TestUtils.selectAll("Dropdown__ListItem-")!
     ).find(el => el.textContent === DateTime.local(2023, 2).monthLong);
     expect(february).toBeTruthy();
-    february!.click();
+    await act(async () => {
+      february!.click();
+    });
     expect(defaultProps.onChange).toHaveBeenCalledWith(
       SCHEDULE_MOCK.id,
       {
@@ -231,15 +253,19 @@ describe("Schedule", () => {
     expect(getByText("Adding ...")).toBeTruthy();
   });
 
-  it("changes timezone", () => {
+  it("changes timezone", async () => {
     render(<Schedule {...defaultProps} />);
     const timezoneDropdown = TestUtils.select(
       "DropdownLink__LinkButton-",
       TestUtils.select("Schedule__Timezone-")!
     )!;
     expect(timezoneDropdown).toBeTruthy();
-    timezoneDropdown.click();
-    TestUtils.select("DropdownLink__ListItem-")!.click();
+    await act(async () => {
+      timezoneDropdown.click();
+    });
+    await act(async () => {
+      TestUtils.select("DropdownLink__ListItem-")!.click();
+    });
     expect(defaultProps.onTimezoneChange).toHaveBeenCalled();
   });
 });

+ 22 - 10
src/components/modules/TransferModule/ScheduleItem/ScheduleItem.spec.tsx

@@ -13,7 +13,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 import { DateTime } from "luxon";
-import React from "react";
+import React, { act } from "react";
 
 import DateUtils from "@src/utils/DateUtils";
 import { render } from "@testing-library/react";
@@ -48,18 +48,24 @@ describe("ScheduleItem", () => {
     expect(getByText(DateTime.local(2023, 4, 4).weekdayLong!)).toBeTruthy();
   });
 
-  it("handles expiration date change", () => {
+  it("handles expiration date change", async () => {
     render(
       <ScheduleItem
         {...defaultProps}
         item={{ ...SCHEDULE_MOCK, enabled: false }}
       />
     );
-    TestUtils.selectAll("DropdownButton__Wrapper-")[5]?.click();
+    await act(async () => {
+      TestUtils.selectAll("DropdownButton__Wrapper-")[5]?.click();
+    });
     const day = document.querySelector(".rdtDay.rdtNew") as HTMLElement;
     expect(day).toBeTruthy();
-    day.click();
-    TestUtils.selectAll("DropdownButton__Wrapper-")[5]?.click();
+    await act(async () => {
+      day.click();
+    });
+    await act(async () => {
+      TestUtils.selectAll("DropdownButton__Wrapper-")[5]?.click();
+    });
     expect(defaultProps.onChange).toHaveBeenCalled();
   });
 
@@ -71,24 +77,30 @@ describe("ScheduleItem", () => {
     ${"minute"} | ${4}       | ${30}                      | ${31}
   `(
     "handles $fieldName change",
-    ({ fieldName, fieldIndex, value, valueIndex }) => {
+    async ({ fieldName, fieldIndex, value, valueIndex }) => {
       render(
         <ScheduleItem
           {...defaultProps}
           item={{ ...SCHEDULE_MOCK, enabled: false }}
         />
       );
-      TestUtils.selectAll("DropdownButton__Wrapper-")[fieldIndex]?.click();
-      TestUtils.selectAll("Dropdown__ListItem-")[valueIndex]?.click();
+      await act(async () => {
+        TestUtils.selectAll("DropdownButton__Wrapper-")[fieldIndex]?.click();
+      });
+      await act(async () => {
+        TestUtils.selectAll("Dropdown__ListItem-")[valueIndex]?.click();
+      });
       expect(defaultProps.onChange).toHaveBeenCalledWith({
         schedule: { [fieldName]: value },
       });
     }
   );
 
-  it("enables item", () => {
+  it("enables item", async () => {
     render(<ScheduleItem {...defaultProps} />);
-    TestUtils.select("Switch__InputWrapper-")!.click();
+    await act(async () => {
+      TestUtils.select("Switch__InputWrapper-")!.click();
+    });
     expect(defaultProps.onChange).toHaveBeenCalledWith(
       {
         enabled: false,

+ 5 - 3
src/components/modules/TransferModule/Tasks/Tasks.spec.tsx

@@ -12,7 +12,7 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-import React from "react";
+import React, { act } from "react";
 
 import { fireEvent, render } from "@testing-library/react";
 import { TASK_MOCK } from "@tests/mocks/ExecutionsMock";
@@ -96,7 +96,7 @@ describe("Tasks", () => {
     expect(taskItem.textContent).toContain("Open: false");
   });
 
-  it("handles depends on click", () => {
+  it("handles depends on click", async () => {
     const { getByTestId } = render(<Tasks {...defaultProps} />);
     const firstTaskItem = getByTestId("TaskItem-task-id");
     const secondTaskItem = getByTestId("TaskItem-task-2");
@@ -112,7 +112,9 @@ describe("Tasks", () => {
       "[data-testid='TaskItem-DependsOn']"
     ) as HTMLElement;
     expect(dependsOn).toBeTruthy();
-    dependsOn!.click();
+    await act(async () => {
+      dependsOn!.click();
+    });
     expect(firstTaskItem.textContent).toContain("Open: true");
   });
 

+ 6 - 4
src/components/modules/TransferModule/TransferDetailsContent/ReplicaDetailsContent.spec.tsx

@@ -12,7 +12,7 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-import React from "react";
+import React, { act } from "react";
 
 import Schedule from "@src/components/modules/TransferModule/Schedule";
 import ScheduleStore from "@src/stores/ScheduleStore";
@@ -41,7 +41,7 @@ jest.mock("@src/components/modules/EndpointModule/EndpointLogos", () => ({
   __esModule: true,
   default: (props: any) => <div>{props.endpoint}</div>,
 }));
-jest.mock("react-router-dom", () => ({ Link: "a" }));
+jest.mock("react-router", () => ({ Link: "a" }));
 jest.mock("@src/utils/Config", () => ({
   config: {
     providerSortPriority: {},
@@ -120,12 +120,14 @@ describe("ReplicaDetailsContent", () => {
     expect(getByTestId("ScheduleComponent")).toBeTruthy();
   });
 
-  it("fires timezone change", () => {
+  it("fires timezone change", async () => {
     const { getByTestId, getByText } = render(
       <ReplicaDetailsContent {...defaultProps} page="schedule" />
     );
     expect(getByText("Timezone: local")).toBeTruthy();
-    getByTestId("ScheduleComponent").click();
+    await act(async () => {
+      getByTestId("ScheduleComponent").click();
+    });
     expect(getByText("Timezone: utc")).toBeTruthy();
   });
 });

+ 11 - 5
src/components/modules/TransferModule/TransferDetailsTable/TransferDetailsTable.spec.tsx

@@ -12,7 +12,7 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-import React from "react";
+import React, { act } from "react";
 
 import { render } from "@testing-library/react";
 import { INSTANCE_MOCK } from "@tests/mocks/InstancesMock";
@@ -68,7 +68,7 @@ describe("TransferDetailsTable", () => {
     expect(getByText("Target")).toBeTruthy();
   });
 
-  it("handles row click", () => {
+  it("handles row click", async () => {
     render(<TransferDetailsTable {...defaultProps} />);
     const rows = TestUtils.selectAll("TransferDetailsTable__Row-");
     expect(rows[0]).toBeTruthy();
@@ -79,13 +79,19 @@ describe("TransferDetailsTable", () => {
     expect(secondArrow()).toBeTruthy();
 
     expect(firstArrow().getAttribute("orientation")).toBe("down");
-    rows[0].click();
+    act(() => {
+      rows[0].click();
+    });
     expect(firstArrow().getAttribute("orientation")).toBe("up");
 
     expect(secondArrow().getAttribute("orientation")).toBe("down");
-    rows[1].click();
+    act(() => {
+      rows[1].click();
+    });
     expect(secondArrow().getAttribute("orientation")).toBe("up");
-    rows[1].click();
+    act(() => {
+      rows[1].click();
+    });
     expect(secondArrow().getAttribute("orientation")).toBe("down");
   });
 });

+ 1 - 1
src/components/modules/UserModule/UserDetailsContent/UserDetailsContent.spec.tsx

@@ -20,7 +20,7 @@ import TestUtils from "@tests/TestUtils";
 
 import UserDetailsContent from "./";
 
-jest.mock("react-router-dom", () => ({ Link: "a" }));
+jest.mock("react-router", () => ({ Link: "a" }));
 
 describe("UserDetailsContent", () => {
   let defaultProps: UserDetailsContent["props"];

+ 1 - 1
src/components/modules/WizardModule/WizardOptions/WizardOptions.spec.tsx

@@ -26,7 +26,7 @@ jest.mock("@src/utils/Config", () => ({
   },
 }));
 jest.mock("react-transition-group", () => ({
-  CSSTransitionGroup: (props: any) => <div>{props.children}</div>,
+  CSSTransition: (props: any) => <div>{props.children}</div>,
 }));
 
 describe("WizardOptions", () => {

+ 7 - 3
src/components/ui/AutocompleteInput/AutocompleteInput.spec.tsx

@@ -12,7 +12,7 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-import React from "react";
+import React, { act } from "react";
 import { render } from "@testing-library/react";
 import TestUtils from "@tests/TestUtils";
 import AutocompleteInput from "./AutocompleteInput";
@@ -35,9 +35,13 @@ describe("AutocompleteInput", () => {
       />
     );
     const inputElement = TestUtils.select("TextInput__Input");
-    inputElement?.focus();
+    act(() => {
+      inputElement?.focus();
+    });
     expect(onFocus).toHaveBeenCalled();
-    inputElement?.blur();
+    act(() => {
+      inputElement?.blur();
+    });
     expect(onBlur).toHaveBeenCalled();
   });
 });

+ 7 - 3
src/components/ui/DatetimePicker/DatetimePicker.spec.tsx

@@ -12,7 +12,7 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-import React from "react";
+import React, { act } from "react";
 
 import DateUtils from "@src/utils/DateUtils";
 import { render } from "@testing-library/react";
@@ -36,12 +36,16 @@ describe("DatetimePicker", () => {
   it("changes the date", () => {
     render(<DatetimePicker onChange={() => {}} timezone="utc" value={DATE} />);
     expect(TestUtils.select("DatetimePicker__Portal")).toBeNull();
-    TestUtils.select("DropdownButton__Wrapper")?.click();
+    act(() => {
+      TestUtils.select("DropdownButton__Wrapper")?.click();
+    });
     expect(TestUtils.select("DatetimePicker__Portal")).not.toBeNull();
     const firstDay = document.querySelector<HTMLElement>(
       'td.rdtDay[data-value="1"]'
     );
-    firstDay?.click();
+    act(() => {
+      firstDay?.click();
+    });
 
     const expected = DateUtils.getUtcDate(DATE)
       .set({ day: 1 })

+ 23 - 11
src/components/ui/Dropdowns/ActionDropdown/ActionDropdown.spec.tsx

@@ -12,7 +12,7 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-import React from "react";
+import React, { act } from "react";
 import { render } from "@testing-library/react";
 import TestUtils from "@tests/TestUtils";
 import ActionDropdown, { DropdownAction } from "./ActionDropdown";
@@ -52,18 +52,22 @@ describe("ActionDropdown", () => {
     );
   });
 
-  it("renders only visible actions", () => {
+  it("renders only visible actions", async () => {
     render(<ActionDropdown actions={ACTIONS} />);
-    TestUtils.select("DropdownButton__Wrapper")!.click();
+    await act(async () => {
+      TestUtils.select("DropdownButton__Wrapper")!.click();
+    });
     expect(TestUtils.selectAll("ActionDropdown__ListItem").length).toBe(3);
     TestUtils.selectAll("ActionDropdown__ListItem").forEach((item, index) => {
       expect(item.textContent).toBe(ACTIONS[index].label);
     });
   });
 
-  it("renders actions with props", () => {
+  it("renders actions with props", async () => {
     render(<ActionDropdown actions={ACTIONS} />);
-    TestUtils.select("DropdownButton__Wrapper")!.click();
+    await act(async () => {
+      TestUtils.select("DropdownButton__Wrapper")!.click();
+    });
     TestUtils.selectAll("ActionDropdown__ListItem").forEach((item, index) => {
       if (ACTIONS[index].disabled) {
         expect(item.hasAttribute("disabled")).toBe(true);
@@ -81,17 +85,25 @@ describe("ActionDropdown", () => {
     });
   });
 
-  it("fires click events correctly", () => {
+  it("fires click events correctly", async () => {
     render(<ActionDropdown actions={ACTIONS} />);
-    TestUtils.select("DropdownButton__Wrapper")!.click();
-    TestUtils.selectAll("ActionDropdown__ListItem").forEach((item, index) => {
-      item.click();
+    await act(async () => {
+      TestUtils.select("DropdownButton__Wrapper")!.click();
+    });
+    const listItems = TestUtils.selectAll("ActionDropdown__ListItem");
+
+    for (let index = 0; index < listItems.length; index++) {
+      const item = listItems[index];
+      await act(async () => {
+        item.click();
+      });
       if (ACTIONS[index].disabled || ACTIONS[index].loading) {
         expect(ACTIONS[index].action).not.toHaveBeenCalled();
       } else {
+        await act(async () => {
         TestUtils.select("DropdownButton__Wrapper")!.click();
+        });
         expect(ACTIONS[index].action).toHaveBeenCalled();
       }
-    });
-  });
+    }});
 });

+ 5 - 3
src/components/ui/Dropdowns/AutocompleteDropdown/AutocompleteDropdown.spec.tsx

@@ -12,7 +12,7 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-import React from "react";
+import React, { act } from "react";
 import { render } from "@testing-library/react";
 import userEvent from "@testing-library/user-event";
 import TestUtils from "@tests/TestUtils";
@@ -44,12 +44,14 @@ describe("AutocompleteDropdown", () => {
     });
   });
 
-  it("fires change on autocomplete item click", () => {
+  it("fires change on autocomplete item click", async () => {
     const onChange = jest.fn();
     render(<AutocompleteDropdown items={ITEMS} onChange={onChange} />);
     userEvent.type(document.querySelector("input")!, "Label B");
 
-    TestUtils.selectAll("AutocompleteDropdown__ListItem-")[1].click();
+    await act(async () => {
+      TestUtils.selectAll("AutocompleteDropdown__ListItem-")[1].click();
+    });
 
     expect(onChange).toHaveBeenCalledWith(ITEMS[3]);
   });

+ 13 - 5
src/components/ui/Dropdowns/Dropdown/Dropdown.spec.tsx

@@ -12,7 +12,7 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-import React from "react";
+import React, { act } from "react";
 import { render } from "@testing-library/react";
 import Dropdown from "@src/components/ui/Dropdowns/Dropdown";
 import TestUtils from "@tests/TestUtils";
@@ -36,13 +36,17 @@ describe("Dropdown", () => {
     );
     const button = TestUtils.select("DropdownButton__Wrapper");
     expect(button).toBeTruthy();
-    button?.click();
+    act(() => {
+      button?.click();
+    });
     expect(TestUtils.selectAll("Dropdown__ListItem-").length).toBe(3);
   });
 
   it("displays duplicated label", () => {
     render(<Dropdown items={ITEMS} />);
-    TestUtils.select("DropdownButton__Wrapper")?.click();
+    act(() => {
+      TestUtils.select("DropdownButton__Wrapper")?.click();
+    });
     expect(TestUtils.selectAll("Dropdown__DuplicatedLabel").length).toBe(2);
     const duplicatedItems = [ITEMS[1], ITEMS[2]];
     TestUtils.selectAll("Dropdown__DuplicatedLabel").forEach((item, index) => {
@@ -61,9 +65,13 @@ describe("Dropdown", () => {
     const onChange = jest.fn();
     render(<Dropdown items={ITEMS} onChange={onChange} />);
     const button = TestUtils.select("DropdownButton__Wrapper");
-    button!.click();
+    act(() => {
+      button!.click();
+    });
     const items = TestUtils.selectAll("Dropdown__ListItem-");
-    items[1]!.click();
+    act(() => {
+      items[1]!.click();
+    });
     expect(onChange).toHaveBeenCalledWith(ITEMS[1]);
   });
 });

+ 10 - 4
src/components/ui/Dropdowns/DropdownFilter/DropdownFilter.spec.tsx

@@ -12,7 +12,7 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-import React from "react";
+import React, { act } from "react";
 import { render } from "@testing-library/react";
 import DropdownFilter from "@src/components/ui/Dropdowns/DropdownFilter";
 import TestUtils from "@tests/TestUtils";
@@ -27,13 +27,17 @@ describe("DropdownFilter", () => {
   it("renders the dropdown", () => {
     render(<DropdownFilter />);
     expect(TestUtils.select("SearchInput__Wrapper")).toBeFalsy();
-    TestUtils.select("DropdownFilter__Button")!.click();
+    act (() => {
+      TestUtils.select("DropdownFilter__Button")!.click();
+    });
     expect(TestUtils.select("SearchInput__Wrapper")).toBeTruthy();
   });
 
   it("displays the search input value", () => {
     render(<DropdownFilter searchValue="Search Value" />);
-    TestUtils.select("DropdownFilter__Button")!.click();
+    act (() => {
+      TestUtils.select("DropdownFilter__Button")!.click();
+    });
     expect(TestUtils.selectInput("TextInput__Input")!.value).toBe(
       "Search Value"
     );
@@ -42,7 +46,9 @@ describe("DropdownFilter", () => {
   it("fires change on search input value change", () => {
     const onChange = jest.fn();
     render(<DropdownFilter onSearchChange={onChange} />);
-    TestUtils.select("DropdownFilter__Button")!.click();
+    act (() => {
+      TestUtils.select("DropdownFilter__Button")!.click();
+    });
     userEvent.type(TestUtils.select("TextInput__Input")!, "Search");
     expect(onChange).toBeCalledTimes(6);
     expect(onChange.mock.calls[0][0]).toBe("S");

+ 4 - 2
src/components/ui/Dropdowns/DropdownFilterGroup/DropdownFilterGroup.spec.tsx

@@ -12,7 +12,7 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-import React from "react";
+import React, { act } from "react";
 import { render } from "@testing-library/react";
 import DropdownFilterGroup from "@src/components/ui/Dropdowns/DropdownFilterGroup";
 import TestUtils from "@tests/TestUtils";
@@ -42,7 +42,9 @@ describe("DropdownFilterGroup", () => {
   it("opens the DropdownLink component with the correct items", () => {
     render(<DropdownFilterGroup items={ITEMS} />);
     const dropdownLinks = TestUtils.selectAll("DropdownLink__LinkButton");
-    dropdownLinks[1].click();
+    act(() => {
+      dropdownLinks[1].click();
+    });
     expect(TestUtils.selectAll("DropdownLink__ListItem-")).toHaveLength(
       ITEMS[1].items.length
     );

+ 16 - 8
src/components/ui/Dropdowns/DropdownLink/DropdownLink.spec.tsx

@@ -12,7 +12,7 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-import React from "react";
+import React, { act } from "react";
 import { render } from "@testing-library/react";
 import TestUtils from "@tests/TestUtils";
 import userEvent from "@testing-library/user-event";
@@ -47,17 +47,23 @@ describe("DropdownLink", () => {
     );
   });
 
-  it("fires selected item change", () => {
+  it("fires selected item change", async () => {
     const onChange = jest.fn();
     render(<DropdownLink items={ITEMS} onChange={onChange} />);
-    TestUtils.select("DropdownLink__LinkButton")?.click();
-    TestUtils.selectAll("DropdownLink__ListItem-")[1].click();
+    await act(async () => {
+      TestUtils.select("DropdownLink__LinkButton")?.click();
+    });
+    await act(async () => {
+      TestUtils.selectAll("DropdownLink__ListItem-")[1].click();
+    });
     expect(onChange).toBeCalledWith(ITEMS[1]);
   });
 
-  it("can be searchable", () => {
+  it("can be searchable", async () => {
     render(<DropdownLink items={ITEMS} searchable />);
-    TestUtils.select("DropdownLink__LinkButton")?.click();
+    await act(async () => {
+      TestUtils.select("DropdownLink__LinkButton")?.click();
+    });
     const input = TestUtils.selectContains("SearchInput__Input")!;
     userEvent.type(input, "A");
     const listItems = () => TestUtils.selectAll("DropdownLink__ListItem-");
@@ -74,9 +80,11 @@ describe("DropdownLink", () => {
     expect(TestUtils.select("DropdownLink__EmptySearch")).toBeTruthy();
   });
 
-  it("highlights the highlighted item", () => {
+  it("highlights the highlighted item", async () => {
     render(<DropdownLink items={ITEMS} highlightedItem={ITEMS[1].value} />);
-    TestUtils.select("DropdownLink__LinkButton")?.click();
+    await act(async () => {
+      TestUtils.select("DropdownLink__LinkButton")?.click();
+    });
     const noHighlightStyle = window.getComputedStyle(
       TestUtils.selectAll("DropdownLink__ListItemLabel")[0]
     );

+ 11 - 5
src/components/ui/Dropdowns/NewItemDropdown/NewItemDropdown.spec.tsx

@@ -12,13 +12,13 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-import React from "react";
+import React, { act } from "react";
 import { render } from "@testing-library/react";
 
 import TestUtils from "@tests/TestUtils";
 import NewItemDropdown from ".";
 
-jest.mock("react-router-dom", () => ({
+jest.mock("react-router", () => ({
   Link: "div",
 }));
 
@@ -31,8 +31,12 @@ describe("NewItemDropdown", () => {
   it("fires change", () => {
     const onChange = jest.fn();
     render(<NewItemDropdown onChange={onChange} />);
-    TestUtils.select("DropdownButton__Wrapper")!.click();
-    TestUtils.selectAll("NewItemDropdown__ListItem")[2].click();
+    act(() => {
+      TestUtils.select("DropdownButton__Wrapper")!.click();
+    });
+    act (() => {
+      TestUtils.selectAll("NewItemDropdown__ListItem")[2].click();
+    });
     expect(onChange).toBeCalledWith(
       expect.objectContaining({ value: "minionPool" })
     );
@@ -40,7 +44,9 @@ describe("NewItemDropdown", () => {
 
   it("has list items with 'to' property", () => {
     render(<NewItemDropdown onChange={() => {}} />);
-    TestUtils.select("DropdownButton__Wrapper")!.click();
+    act(() => {
+      TestUtils.select("DropdownButton__Wrapper")!.click();
+    });
     const listItems = TestUtils.selectAll("NewItemDropdown__ListItem");
     expect(listItems[0].getAttribute("to")).toBe("/wizard/migration");
     expect(listItems[1].getAttribute("to")).toBe("#");

+ 17 - 9
src/components/ui/Dropdowns/NotificationDropdown/NotificationDropdown.spec.tsx

@@ -12,14 +12,14 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-import React from "react";
+import React, { act } from "react";
 import { render } from "@testing-library/react";
 import NotificationDropdown from "@src/components/ui/Dropdowns/NotificationDropdown";
 
 import type { NotificationItemData } from "@src/@types/NotificationItem";
 import TestUtils from "@tests/TestUtils";
 
-jest.mock("react-router-dom", () => ({ Link: "div" }));
+jest.mock("react-router", () => ({ Link: "div" }));
 
 const ITEMS: NotificationItemData[] = [
   {
@@ -52,9 +52,11 @@ describe("NotificationDropdown", () => {
     expect(TestUtils.select("NotificationDropdown__BellIcon")).toBeTruthy();
   });
 
-  it("shows items on click", () => {
+  it("shows items on click", async () => {
     render(<NotificationDropdown items={ITEMS} onClose={() => {}} />);
-    TestUtils.select("NotificationDropdown__Icon")!.click();
+    await act(async () => {
+      TestUtils.select("NotificationDropdown__Icon")!.click();
+    });
     const listItems = TestUtils.selectAll("NotificationDropdown__ListItem");
     expect(listItems[0].getAttribute("to")).toBe(
       `/${ITEMS[0].type}s/${ITEMS[0].id}`
@@ -79,17 +81,23 @@ describe("NotificationDropdown", () => {
     ).toBe(ITEMS[2].description);
   });
 
-  it("fires onClose on item click", () => {
+  it("fires onClose on item click", async () => {
     const onClose = jest.fn();
     render(<NotificationDropdown items={ITEMS} onClose={onClose} />);
-    TestUtils.select("NotificationDropdown__Icon")!.click();
-    TestUtils.selectAll("NotificationDropdown__ListItem")[1].click();
+    await act(async () => {
+      TestUtils.select("NotificationDropdown__Icon")!.click();
+    });
+    await act(async () => {
+      TestUtils.selectAll("NotificationDropdown__ListItem")[1].click();
+    });
     expect(onClose).toHaveBeenCalled();
   });
 
-  it("renders unseed badge", () => {
+  it("renders unseed badge", async () => {
     render(<NotificationDropdown items={ITEMS} onClose={() => {}} />);
-    TestUtils.select("NotificationDropdown__Icon")!.click();
+    await act(async () => {
+      TestUtils.select("NotificationDropdown__Icon")!.click();
+    });
     const listItems = TestUtils.selectAll("NotificationDropdown__ListItem");
     expect(
       TestUtils.select("NotificationDropdown__Badge", listItems[0])

+ 14 - 6
src/components/ui/Dropdowns/UserDropdown/UserDropdown.spec.tsx

@@ -12,13 +12,13 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-import React from "react";
+import React, { act } from "react";
 import { render } from "@testing-library/react";
 import TestUtils from "@tests/TestUtils";
 import { User } from "@src/@types/User";
 import UserDropdown from ".";
 
-jest.mock("react-router-dom", () => ({ Link: "div" }));
+jest.mock("react-router", () => ({ Link: "div" }));
 
 const USER: User = {
   id: "user-id",
@@ -33,7 +33,9 @@ const USER: User = {
 describe("UserDropdown", () => {
   it("renders no user", () => {
     render(<UserDropdown user={null} onItemClick={() => {}} />);
-    TestUtils.select("UserDropdown__Icon")?.click();
+    act (() => {
+      TestUtils.select("UserDropdown__Icon")?.click();
+    });
     expect(TestUtils.select("UserDropdown__Label")?.textContent).toBe(
       "No signed in user"
     );
@@ -41,7 +43,9 @@ describe("UserDropdown", () => {
 
   it("renders user menu", () => {
     render(<UserDropdown user={USER} onItemClick={() => {}} />);
-    TestUtils.select("UserDropdown__Icon")?.click();
+    act (() => {
+      TestUtils.select("UserDropdown__Icon")?.click();
+    });
     expect(TestUtils.select("UserDropdown__Username")?.textContent).toBe(
       USER.name
     );
@@ -56,8 +60,12 @@ describe("UserDropdown", () => {
   it("fires item click", () => {
     const onItemClick = jest.fn();
     render(<UserDropdown user={USER} onItemClick={onItemClick} />);
-    TestUtils.select("UserDropdown__Icon")?.click();
-    TestUtils.selectAll("UserDropdown__Label")[2].click();
+    act (() => {
+      TestUtils.select("UserDropdown__Icon")?.click();
+    });
+    act (() => {
+      TestUtils.selectAll("UserDropdown__Label")[2].click();
+    });
     expect(onItemClick).toHaveBeenCalledWith(
       expect.objectContaining({ value: "signout" })
     );

+ 13 - 7
src/components/ui/FieldInput/FieldInput.spec.tsx

@@ -12,7 +12,7 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-import React from "react";
+import React, { act } from "react";
 import { render } from "@testing-library/react";
 import TestUtils from "@tests/TestUtils";
 import userEvent from "@testing-library/user-event";
@@ -45,7 +45,7 @@ describe("FieldInput", () => {
     );
   });
 
-  it("renders string field with enumerator", () => {
+  it("renders string field with enumerator", async () => {
     const { rerender } = render(
       <FieldInput
         name="Field Name"
@@ -54,7 +54,9 @@ describe("FieldInput", () => {
         enum={["foo", "bar"]}
       />
     );
-    TestUtils.select("DropdownButton__Wrapper")?.click();
+    await act(async () => {
+      TestUtils.select("DropdownButton__Wrapper")?.click();
+    });
     expect(TestUtils.selectAll("Dropdown__ListItem-")).toHaveLength(2);
     expect(TestUtils.select("Dropdown__ListItem-")?.textContent).toBe("foo");
     rerender(
@@ -122,7 +124,7 @@ describe("FieldInput", () => {
     expect(document.querySelector("input")?.getAttribute("type")).toBe("file");
   });
 
-  it("renders integer input", () => {
+  it("renders integer input", async () => {
     const { rerender } = render(
       <FieldInput
         name="Field Name"
@@ -143,7 +145,9 @@ describe("FieldInput", () => {
         value={5}
       />
     );
-    TestUtils.select("DropdownButton__Wrapper")?.click();
+    await act(async () => {
+      TestUtils.select("DropdownButton__Wrapper")?.click();
+    });
     expect(TestUtils.selectAll("Dropdown__ListItem-")).toHaveLength(8);
     expect(TestUtils.selectAll("Dropdown__ListItem-")[1].textContent).toBe("2");
     expect(TestUtils.select("DropdownButton__Label")?.textContent).toBe("5");
@@ -156,7 +160,7 @@ describe("FieldInput", () => {
     ).toBeTruthy();
   });
 
-  it("renders array dropdown", () => {
+  it("renders array dropdown", async () => {
     render(
       <FieldInput
         name="Field Name"
@@ -168,7 +172,9 @@ describe("FieldInput", () => {
     expect(TestUtils.select("DropdownButton__Label")?.textContent).toBe(
       "bar, baz"
     );
-    TestUtils.select("DropdownButton__Wrapper")?.click();
+    await act(async () => {
+      TestUtils.select("DropdownButton__Wrapper")?.click();
+    });
   });
 
   it("renders object field", () => {

+ 13 - 7
src/components/ui/Lists/FilterList/FilterList.spec.tsx

@@ -12,7 +12,7 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-import React from "react";
+import React, { act } from "react";
 import styled from "styled-components";
 import { render } from "@testing-library/react";
 import FilterList from "@src/components/ui/Lists/FilterList";
@@ -103,9 +103,11 @@ describe("FilterList", () => {
     );
   });
 
-  it("filters items", () => {
+  it("filters items", async () => {
     render(FilterListWrap());
-    TestUtils.selectAll("MainListFilter__FilterItem")[3].click();
+    await act(async () => {
+      TestUtils.selectAll("MainListFilter__FilterItem")[3].click();
+    });
     const listItems = () =>
       TestUtils.selectAll("FilterListspec__MainListItem-");
     expect(listItems()).toHaveLength(2);
@@ -131,9 +133,11 @@ describe("FilterList", () => {
     expect(TestUtils.select("MainList__NoResults")).toBeTruthy();
   });
 
-  it("goes to next page", () => {
+  it("goes to next page", async () => {
     render(FilterListWrap());
-    TestUtils.select("Pagination__PageNext")?.click();
+    await act(async () => {
+      TestUtils.select("Pagination__PageNext")?.click();
+    });
 
     expect(TestUtils.select("Pagination__PageNumber")?.textContent).toBe(
       "2 of 2"
@@ -150,14 +154,16 @@ describe("FilterList", () => {
     expect(onItemClick).toHaveBeenCalledWith(ITEMS[1]);
   });
 
-  it("selects items", () => {
+  it("selects items", async () => {
     const onSelectedItemsChange = jest.fn();
     render(FilterListWrap({ onSelectedItemsChange }));
     const checkbox = TestUtils.selectAll(
       "FilterListspec__MainListItem-"
     )[1].querySelector("input") as HTMLInputElement;
     expect(checkbox.checked).toBe(false);
-    checkbox.click();
+    await act(async () => {
+      checkbox.click();
+    });
     expect(checkbox.checked).toBe(true);
     expect(TestUtils.select("MainListFilter__SelectionText")?.textContent).toBe(
       "1 of 4\u00a0test item(s) selected"

+ 16 - 8
src/components/ui/Lists/MainListFilter/MainListFilter.spec.tsx

@@ -12,7 +12,7 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-import React, { useState } from "react";
+import React, { useState, act } from "react";
 import { render } from "@testing-library/react";
 import userEvent from "@testing-library/user-event";
 import MainListFilter from "@src/components/ui/Lists/MainListFilter";
@@ -82,16 +82,20 @@ describe("MainListFilter", () => {
     );
   });
 
-  it("renders actions", () => {
+  it("renders actions", async () => {
     render(<MainListFilterWrapper />);
-    TestUtils.select("DropdownButton__Wrapper")?.click();
+    await act(async () => {
+      TestUtils.select("DropdownButton__Wrapper")?.click();
+    });
     const actions = TestUtils.selectAll("ActionDropdown__ListItem-");
     expect(actions).toHaveLength(ACTIONS.length);
     expect(actions[0].textContent).toBe(ACTIONS[0].label);
     expect(actions[0].hasAttribute("disabled")).toBeFalsy();
     expect(actions[1].hasAttribute("disabled")).toBeTruthy();
-    actions[0].click();
-    actions[1].click();
+    await act(async () => {
+      actions[0].click();
+      actions[1].click();
+    });
     expect(ACTIONS[0].action).toHaveBeenCalled();
     expect(ACTIONS[1].action).not.toHaveBeenCalled();
   });
@@ -103,20 +107,24 @@ describe("MainListFilter", () => {
     expect(onFilterItemClick).toHaveBeenCalledWith(FILTER_ITEMS[1]);
   });
 
-  it("has select all change", () => {
+  it("has select all change", async () => {
     const onSelectAllChange = jest.fn();
     render(<MainListFilterWrapper onSelectAllChange={onSelectAllChange} />);
 
     const checkbox = TestUtils.select("Checkbox__Wrapper")!;
     const style = () => window.getComputedStyle(checkbox);
     expect(TestUtils.rgbToHex(style().backgroundColor)).toBe("white");
-    checkbox.click();
+    await act(async () => {
+      checkbox.click();
+    });
     expect(TestUtils.rgbToHex(style().backgroundColor)).toBe(
       ThemePalette.primary
     );
 
     expect(onSelectAllChange).toHaveBeenCalledWith(true);
-    checkbox.click();
+    await act(async () => {
+      checkbox.click();
+    });
     expect(onSelectAllChange).toHaveBeenCalledWith(false);
     expect(TestUtils.rgbToHex(style().backgroundColor)).toBe("white");
   });

+ 16 - 8
src/components/ui/Lists/MainMultiFilterList/MainMultiFilterList.spec.tsx

@@ -12,7 +12,7 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-import React, { useState } from "react";
+import React, { useState, act } from "react";
 import { render } from "@testing-library/react";
 import userEvent from "@testing-library/user-event";
 import MainMultiFilterList from "@src/components/ui/Lists/MainMultiFilterList";
@@ -82,16 +82,20 @@ describe("MainMultiFilterList", () => {
     ).toBe("1 of 3\u00a0test item(s) selected");
   });
 
-  it("renders actions", () => {
+  it("renders actions", async () => {
     render(<MainMultiFilterListWrapper />);
-    TestUtils.select("DropdownButton__Wrapper")?.click();
+    await act(async () => {
+      TestUtils.select("DropdownButton__Wrapper")?.click();
+    });
     const actions = TestUtils.selectAll("ActionDropdown__ListItem-");
     expect(actions).toHaveLength(ACTIONS.length);
     expect(actions[0].textContent).toBe(ACTIONS[0].label);
     expect(actions[0].hasAttribute("disabled")).toBeFalsy();
     expect(actions[1].hasAttribute("disabled")).toBeTruthy();
-    actions[0].click();
-    actions[1].click();
+    await act(async () => {
+      actions[0].click();
+      actions[1].click();
+    });
     expect(ACTIONS[0].action).toHaveBeenCalled();
     expect(ACTIONS[1].action).not.toHaveBeenCalled();
   });
@@ -105,7 +109,7 @@ describe("MainMultiFilterList", () => {
     expect(onFilterItemClick).toHaveBeenCalledWith(FILTER_ITEMS[1]);
   });
 
-  it("has select all change", () => {
+  it("has select all change", async () => {
     const onSelectAllChange = jest.fn();
     render(
       <MainMultiFilterListWrapper onSelectAllChange={onSelectAllChange} />
@@ -114,13 +118,17 @@ describe("MainMultiFilterList", () => {
     const checkbox = TestUtils.select("Checkbox__Wrapper")!;
     const style = () => window.getComputedStyle(checkbox);
     expect(TestUtils.rgbToHex(style().backgroundColor)).toBe("white");
-    checkbox.click();
+    await act(async () => {
+      checkbox.click();
+    });
     expect(TestUtils.rgbToHex(style().backgroundColor)).toBe(
       ThemePalette.primary
     );
 
     expect(onSelectAllChange).toHaveBeenCalledWith(true);
-    checkbox.click();
+    await act(async () => {
+      checkbox.click();
+    });
     expect(onSelectAllChange).toHaveBeenCalledWith(false);
     expect(TestUtils.rgbToHex(style().backgroundColor)).toBe("white");
   });

+ 2 - 2
src/components/ui/Logo/Logo.spec.tsx

@@ -18,7 +18,7 @@ import Logo from "@src/components/ui/Logo";
 import { render } from "@testing-library/react";
 import TestUtils from "@tests/TestUtils";
 
-jest.mock("react-router-dom", () => ({ Link: "a" }));
+jest.mock("react-router", () => ({ Link: "a" }));
 describe("Logo", () => {
   it("renders", () => {
     render(<Logo />);
@@ -28,7 +28,7 @@ describe("Logo", () => {
   it("accepts custom 'to' property", () => {
     render(<Logo to="#testing" />);
     expect(TestUtils.select("Logo__LinkStyled")?.getAttribute("to")).toBe(
-      "#testing"
+      "../#testing",
     );
   });
 });

+ 4 - 2
src/components/ui/PasswordValue/PasswordValue.spec.tsx

@@ -12,7 +12,7 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-import React from "react";
+import React, { act } from "react";
 import { render } from "@testing-library/react";
 import PasswordValue from "@src/components/ui/PasswordValue";
 import TestUtils from "@tests/TestUtils";
@@ -26,7 +26,9 @@ describe("PasswordValue", () => {
   });
   it("reveals the password on click", () => {
     render(<PasswordValue value="the_secret" />);
-    TestUtils.select("PasswordValue__Value")?.click();
+    act(() => {
+      TestUtils.select("PasswordValue__Value")?.click();
+    });
     expect(TestUtils.select("PasswordValue__Value")?.textContent).toBe(
       "the_secret"
     );

+ 19 - 10
src/components/ui/PropertiesTable/PropertiesTable.spec.tsx

@@ -12,7 +12,7 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-import React from "react";
+import React, { act } from "react";
 import { render } from "@testing-library/react";
 import PropertiesTable from "@src/components/ui/PropertiesTable";
 import { Field } from "@src/@types/Field";
@@ -42,7 +42,7 @@ const PROPERTIES: Field[] = [
 ];
 
 describe("PropertiesTable", () => {
-  it("renders all properties", () => {
+  it("renders all properties", async () => {
     render(
       <PropertiesTable
         properties={PROPERTIES}
@@ -53,8 +53,9 @@ describe("PropertiesTable", () => {
       />
     );
     expect(TestUtils.selectInput("TextInput__Input")?.value).toBe("name-value");
-
-    TestUtils.select("DropdownButton__Wrapper")?.click();
+    await act(async () => {
+      TestUtils.select("DropdownButton__Wrapper")?.click();
+    });
     const listItems = TestUtils.selectAll("Dropdown__ListItem-");
     expect(listItems.length).toBe(PROPERTIES[1].enum!.length + 1);
     expect(listItems[2].textContent).toBe("B");
@@ -80,7 +81,7 @@ describe("PropertiesTable", () => {
     expect(onChange).toHaveBeenCalledWith(PROPERTIES[0], "new-value");
   });
 
-  it("dispatches dropdown change", () => {
+  it("dispatches dropdown change", async () => {
     const onChange = jest.fn();
     render(
       <PropertiesTable
@@ -89,12 +90,16 @@ describe("PropertiesTable", () => {
         valueCallback={() => {}}
       />
     );
-    TestUtils.select("DropdownButton__Wrapper")!.click();
-    TestUtils.selectAll("Dropdown__ListItem-")[2]!.click();
+    await act(async () => {
+      TestUtils.select("DropdownButton__Wrapper")!.click();
+    });
+    await act(async () => {
+      TestUtils.selectAll("Dropdown__ListItem-")[2]!.click();
+    });
     expect(onChange).toHaveBeenCalledWith(PROPERTIES[1], "b");
   });
 
-  it("dispatches switch change", () => {
+  it("dispatches switch change", async () => {
     const onChange = jest.fn();
     render(
       <PropertiesTable
@@ -108,10 +113,14 @@ describe("PropertiesTable", () => {
       "Switch__InputWrapper"
     );
 
-    nonNullableSwitch.click();
+    await act(async () => {
+      nonNullableSwitch.click();
+    });
     expect(onChange).toHaveBeenCalledWith(PROPERTIES[2], false);
 
-    nullableSwitch.click();
+    await act(async () => {
+      nullableSwitch.click();
+    });
     expect(onChange).toHaveBeenCalledWith(PROPERTIES[3], null);
   });
 });

+ 4 - 2
src/components/ui/SearchInput/SearchInput.spec.tsx

@@ -12,7 +12,7 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-import React from "react";
+import React, { act } from "react";
 import { render } from "@testing-library/react";
 import TestUtils from "@tests/TestUtils";
 import userEvent from "@testing-library/user-event";
@@ -37,7 +37,9 @@ describe("SearchInput", () => {
     const style = () =>
       window.getComputedStyle(TestUtils.selectInput("TextInput__Input")!);
     expect(style().width).toBe("50px");
-    TestUtils.select("SearchButton__Wrapper")!.click();
+    act(() => {
+      TestUtils.select("SearchButton__Wrapper")!.click();
+    });
     // wait 500 ms for animation
     await new Promise(resolve => {
       setTimeout(resolve, 500);

+ 44 - 19
src/components/ui/Stepper/Stepper.spec.tsx

@@ -12,7 +12,7 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-import React from "react";
+import React, { act } from "react";
 import { render } from "@testing-library/react";
 import TestUtils from "@tests/TestUtils";
 import userEvent from "@testing-library/user-event";
@@ -24,19 +24,23 @@ describe("Stepper", () => {
     expect(TestUtils.selectInput("Stepper__Input")?.value).toBe("Not Set");
   });
 
-  it("changes input value on step button press", () => {
+  it("changes input value on step button press", async () => {
     const onChange = jest.fn();
     render(<Stepper value={10} onChange={onChange} />);
     expect(TestUtils.selectInput("Stepper__Input")?.value).toBe("10");
 
-    TestUtils.select("Stepper__StepButtonUp")!.click();
+    await act(async () => {
+      TestUtils.select("Stepper__StepButtonUp")!.click();
+    });
     expect(onChange).toHaveBeenCalledWith(11);
 
-    TestUtils.select("Stepper__StepButtonDown")!.click();
+    await act(async () => {
+      TestUtils.select("Stepper__StepButtonDown")!.click();
+    });
     expect(onChange).toHaveBeenCalledWith(9);
   });
 
-  it("abides by the minimum and maximum", () => {
+  it("abides by the minimum and maximum", async () => {
     let value: number | null = 13;
     const onChange = (v: number | null) => {
       value = v;
@@ -55,36 +59,52 @@ describe("Stepper", () => {
 
     rerenderWithValue();
     expect(TestUtils.selectInput("Stepper__Input")?.value).toBe("13");
-    TestUtils.select("Stepper__StepButtonUp")!.click();
+    await act(async () => {
+      TestUtils.select("Stepper__StepButtonUp")!.click();
+    });
     expect(value).toBe(14);
 
     rerenderWithValue();
-    TestUtils.select("Stepper__StepButtonUp")!.click();
+    await act(async () => {
+      TestUtils.select("Stepper__StepButtonUp")!.click();
+    });
     expect(value).toBe(15);
 
     rerenderWithValue();
-    TestUtils.select("Stepper__StepButtonUp")!.click();
+    await act(async () => {
+      TestUtils.select("Stepper__StepButtonUp")!.click();
+    });
     expect(value).toBe(15);
 
     rerenderWithValue();
-    TestUtils.select("Stepper__StepButtonDown")!.click();
+    await act(async () => {
+      TestUtils.select("Stepper__StepButtonDown")!.click();
+    });
     expect(value).toBe(14);
 
     value = 7;
     rerenderWithValue();
-    TestUtils.select("Stepper__StepButtonDown")!.click();
+    await act(async () => {
+      TestUtils.select("Stepper__StepButtonDown")!.click();
+    });
     expect(value).toBe(6);
 
     rerenderWithValue();
-    TestUtils.select("Stepper__StepButtonDown")!.click();
+    await act(async () => {
+      TestUtils.select("Stepper__StepButtonDown")!.click();
+    });
     expect(value).toBe(5);
 
     rerenderWithValue();
-    TestUtils.select("Stepper__StepButtonDown")!.click();
+    await act(async () => {
+      TestUtils.select("Stepper__StepButtonDown")!.click();
+    });
     expect(value).toBe(5);
 
     rerenderWithValue();
-    TestUtils.select("Stepper__StepButtonUp")!.click();
+    await act(async () => {
+      TestUtils.select("Stepper__StepButtonUp")!.click();
+    });
     expect(value).toBe(6);
   });
 
@@ -97,7 +117,7 @@ describe("Stepper", () => {
     ${"3"}     | ${5}
   `(
     "dispatches value $dispatchedValue when typing $typedValue",
-    ({ typedValue, dispatchedValue }) => {
+    async ({ typedValue, dispatchedValue }) => {
       const inputEl = () => TestUtils.selectInput("Stepper__Input")!;
       const onChange = jest.fn();
       render(
@@ -106,21 +126,26 @@ describe("Stepper", () => {
 
       userEvent.clear(inputEl());
       userEvent.paste(inputEl(), typedValue);
-      inputEl().blur();
+      await act(async () => {
+        inputEl().blur();
+      });
       expect(onChange).toHaveBeenCalledWith(dispatchedValue);
     }
   );
 
-  it("increments and decrements on arrow keys press", () => {
+  it("increments and decrements on arrow keys press", async () => {
     const onChange = jest.fn();
     render(<Stepper value={7} onChange={onChange} minimum={5} maximum={10} />);
     const inputEl = () => TestUtils.selectInput("Stepper__Input")!;
     userEvent.type(inputEl(), "{ArrowUp}");
-    inputEl().blur();
+    await act(async () => {
+      inputEl().blur();
+    });
     expect(onChange).toHaveBeenCalledWith(8);
-
     userEvent.type(inputEl(), "{ArrowDown}");
-    inputEl().blur();
+    await act(async () => {
+      inputEl().blur();
+    });
     expect(onChange).toHaveBeenCalledWith(6);
   });
 });

+ 9 - 4
src/components/ui/Switch/Switch.spec.tsx

@@ -12,7 +12,7 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-import React from "react";
+import React, { act } from "react";
 import { render } from "@testing-library/react";
 import TestUtils from "@tests/TestUtils";
 import { ThemePalette } from "@src/components/Theme";
@@ -61,7 +61,7 @@ describe("Switch", () => {
     expect(onChange).toBeCalledWith(false);
   });
 
-  it("dispatches null when in tristate mode", () => {
+  it("dispatches null when in tristate mode", async () => {
     let value: boolean | null = true;
     const onChange = (newValue: boolean | null) => {
       value = newValue;
@@ -73,7 +73,9 @@ describe("Switch", () => {
       rerender(<Switch onChange={onChange} checked={value} triState />);
     };
 
-    TestUtils.select("Switch__InputWrapper")!.click();
+    await act(async () => {
+      TestUtils.select("Switch__InputWrapper")!.click();
+    });
     expect(value).toBe(null);
 
     rerenderWithValue();
@@ -81,7 +83,10 @@ describe("Switch", () => {
     expect(value).toBe(false);
 
     rerenderWithValue();
-    TestUtils.select("Switch__InputWrapper")!.click();
+    
+    await act(async () => {
+      TestUtils.select("Switch__InputWrapper")!.click();
+    });
     expect(value).toBe(null);
 
     rerenderWithValue();