diff --git a/src/app/App.tsx b/src/app/App.tsx index 5b8f745b0a..62e1249e2e 100644 --- a/src/app/App.tsx +++ b/src/app/App.tsx @@ -1,5 +1,5 @@ import type { ReactNode } from "react"; -import { useEffect } from "react"; +import { Suspense, useEffect } from "react"; import { Notification } from "@canonical/react-components"; import { usePrevious } from "@canonical/react-components/dist/hooks"; @@ -197,7 +197,17 @@ export const App = (): JSX.Element => { )} - {content} + } + sidePanelContent={null} + sidePanelTitle={null} + /> + } + > + {content} + diff --git a/src/app/Routes.test.tsx b/src/app/Routes.test.tsx index dc03f499db..f0a5b4bbad 100644 --- a/src/app/Routes.test.tsx +++ b/src/app/Routes.test.tsx @@ -4,6 +4,7 @@ import Routes from "./Routes"; import type { RootState } from "./store/root/types"; import urls from "@/app/base/urls"; +import { LONG_TIMEOUT } from "@/testing/constants"; import { rootState as rootStateFactory, controller as controllerFactory, @@ -184,7 +185,10 @@ describe("Routes", () => { state, routePattern: "/*", }); - await waitFor(() => expect(document.title).toBe(`${title} | MAAS`)); + await waitFor(() => expect(document.title).toBe(`${title} | MAAS`), { + // Wait for pages with redirects + timeout: LONG_TIMEOUT, + }); }); }); @@ -194,7 +198,9 @@ describe("Routes", () => { route: path, state, }); - expect(window.location.pathname).toBe(`${path}/summary`); + await waitFor(() => + expect(window.location.pathname).toBe(`${path}/summary`) + ); }); }); @@ -206,19 +212,27 @@ describe("Routes", () => { expect(window.location.pathname).toBe(urls.machines.index); }); - it("redirects from Settings base URL to configuration", () => { + it("redirects from Settings base URL to configuration", async () => { renderWithBrowserRouter(, { route: urls.settings.index, state, }); - expect(window.location.pathname).toBe(urls.settings.configuration.index); + await waitFor(() => + expect(window.location.pathname).toBe(urls.settings.configuration.index) + ); }); - it("redirects from Preferences base URL to Details", () => { + it("redirects from Preferences base URL to Details", async () => { renderWithBrowserRouter(, { route: urls.preferences.index, state, }); - expect(window.location.pathname).toBe(urls.preferences.details); + await waitFor( + () => expect(window.location.pathname).toBe(urls.preferences.details), + { + // Wait for pages with redirects + timeout: LONG_TIMEOUT, + } + ); }); }); diff --git a/src/app/Routes.tsx b/src/app/Routes.tsx index 40b1d41516..00d3d24ce3 100644 --- a/src/app/Routes.tsx +++ b/src/app/Routes.tsx @@ -1,32 +1,43 @@ +import { lazy } from "react"; + import { Redirect } from "react-router-dom"; import { Route, Routes as ReactRouterRoutes } from "react-router-dom-v5-compat"; import ErrorBoundary from "@/app/base/components/ErrorBoundary"; import urls from "@/app/base/urls"; import NotFound from "@/app/base/views/NotFound"; -import ControllerDetails from "@/app/controllers/views/ControllerDetails"; -import ControllerList from "@/app/controllers/views/ControllerList"; -import DeviceDetails from "@/app/devices/views/DeviceDetails"; -import DeviceList from "@/app/devices/views/DeviceList"; -import DomainDetails from "@/app/domains/views/DomainDetails"; -import DomainsList from "@/app/domains/views/DomainsList"; -import ImageList from "@/app/images/views/ImageList"; -import Intro from "@/app/intro/views/Intro"; -import KVM from "@/app/kvm/views/KVM"; -import MachineDetails from "@/app/machines/views/MachineDetails"; -import Machines from "@/app/machines/views/Machines"; -import NetworkDiscovery from "@/app/networkDiscovery/views/NetworkDiscovery"; -import Pools from "@/app/pools/views/Pools"; -import Preferences from "@/app/preferences/views/Preferences"; -import Settings from "@/app/settings/views/Settings"; -import FabricDetails from "@/app/subnets/views/FabricDetails"; -import SpaceDetails from "@/app/subnets/views/SpaceDetails"; -import SubnetDetails from "@/app/subnets/views/SubnetDetails"; -import SubnetsList from "@/app/subnets/views/SubnetsList"; -import VLANDetails from "@/app/subnets/views/VLANDetails"; -import Tags from "@/app/tags/views/Tags"; -import ZoneDetails from "@/app/zones/views/ZoneDetails"; -import ZonesList from "@/app/zones/views/ZonesList"; + +const ControllerDetails = lazy( + () => import("@/app/controllers/views/ControllerDetails") +); +const ControllerList = lazy( + () => import("@/app/controllers/views/ControllerList") +); +const DeviceDetails = lazy(() => import("@/app/devices/views/DeviceDetails")); +const DeviceList = lazy(() => import("@/app/devices/views/DeviceList")); +const DomainDetails = lazy(() => import("@/app/domains/views/DomainDetails")); +const DomainsList = lazy(() => import("@/app/domains/views/DomainsList")); +const ImageList = lazy(() => import("@/app/images/views/ImageList")); +const Intro = lazy(() => import("@/app/intro/views/Intro")); +const KVM = lazy(() => import("@/app/kvm/views/KVM")); +const MachineDetails = lazy( + () => import("@/app/machines/views/MachineDetails") +); +const Machines = lazy(() => import("@/app/machines/views/Machines")); +const NetworkDiscovery = lazy( + () => import("@/app/networkDiscovery/views/NetworkDiscovery") +); +const Pools = lazy(() => import("@/app/pools/views/Pools")); +const Preferences = lazy(() => import("@/app/preferences/views/Preferences")); +const Settings = lazy(() => import("@/app/settings/views/Settings")); +const FabricDetails = lazy(() => import("@/app/subnets/views/FabricDetails")); +const SpaceDetails = lazy(() => import("@/app/subnets/views/SpaceDetails")); +const SubnetDetails = lazy(() => import("@/app/subnets/views/SubnetDetails")); +const SubnetsList = lazy(() => import("@/app/subnets/views/SubnetsList")); +const VLANDetails = lazy(() => import("@/app/subnets/views/VLANDetails")); +const Tags = lazy(() => import("@/app/tags/views/Tags")); +const ZoneDetails = lazy(() => import("@/app/zones/views/ZoneDetails")); +const ZonesList = lazy(() => import("@/app/zones/views/ZonesList")); const Routes = (): JSX.Element => ( diff --git a/src/app/base/hooks/base.test.tsx b/src/app/base/hooks/base.test.tsx index 3a37010a49..28270656e1 100644 --- a/src/app/base/hooks/base.test.tsx +++ b/src/app/base/hooks/base.test.tsx @@ -8,8 +8,11 @@ import { useProcessing, useScrollOnRender, useScrollToTop, + useWindowTitle, } from "./base"; +import { renderHookWithMockStore } from "@/testing/utils"; + const mockUseLocationValue = { pathname: "/original-pathname", search: "", @@ -21,279 +24,292 @@ vi.mock("react-router-dom", () => ({ useLocation: () => mockUseLocationValue, })); -describe("hooks", () => { - describe("useScrollOnRender", () => { - let html: HTMLHtmlElement | null; - let scrollToSpy: Mock; - let targetNode: HTMLElement; - - beforeEach(() => { - global.innerHeight = 500; - // eslint-disable-next-line testing-library/no-node-access - html = document.querySelector("html"); - scrollToSpy = vi.fn(); - global.scrollTo = scrollToSpy; - targetNode = document.createElement("div"); - }); +describe("useWindowTitle", () => { + it("sets the window title", () => { + const { rerender } = renderHookWithMockStore(() => useWindowTitle("Test")); + expect(document.title).toBe("Test | MAAS"); + rerender(); + expect(document.title).toBe("Test | MAAS"); + }); + it("keeps the window title unchanged on unmount", () => { + const { unmount } = renderHookWithMockStore(() => useWindowTitle("Test")); + expect(document.title).toBe("Test | MAAS"); + unmount(); + expect(document.title).toBe("Test | MAAS"); + }); +}); - afterEach(() => { - if (html) { - html.scrollTop = 0; - } - }); +describe("useScrollOnRender", () => { + let html: HTMLHtmlElement | null; + let scrollToSpy: Mock; + let targetNode: HTMLElement; + + beforeEach(() => { + global.innerHeight = 500; + // eslint-disable-next-line testing-library/no-node-access + html = document.querySelector("html"); + scrollToSpy = vi.fn(); + global.scrollTo = scrollToSpy; + targetNode = document.createElement("div"); + }); - it("does not scroll if the target is on screen", () => { - if (html) { - html.scrollTop = 10; - } - const { result } = renderHook(() => useScrollOnRender()); - targetNode.getBoundingClientRect = () => ({ y: 10 } as DOMRect); - result.current(targetNode); - expect(scrollToSpy).not.toHaveBeenCalled(); - }); + afterEach(() => { + if (html) { + html.scrollTop = 0; + } + }); - it("scrolls if the target is off the bottom of the screen", () => { - if (html) { - html.scrollTop = 100; - } - const { result } = renderHook(() => useScrollOnRender()); - targetNode.getBoundingClientRect = () => ({ y: 1000 } as DOMRect); - result.current(targetNode); - expect(scrollToSpy).toHaveBeenCalledWith({ - top: 1000, - left: 0, - behavior: "smooth", - }); - }); + it("does not scroll if the target is on screen", () => { + if (html) { + html.scrollTop = 10; + } + const { result } = renderHook(() => useScrollOnRender()); + targetNode.getBoundingClientRect = () => ({ y: 10 } as DOMRect); + result.current(targetNode); + expect(scrollToSpy).not.toHaveBeenCalled(); + }); - it("scrolls if the target is off the top of the screen", () => { - if (html) { - html.scrollTop = 1000; - } - const { result } = renderHook(() => useScrollOnRender()); - targetNode.getBoundingClientRect = () => ({ y: 10 } as DOMRect); - result.current(targetNode); - expect(scrollToSpy).toHaveBeenCalledWith({ - top: 10, - left: 0, - behavior: "smooth", - }); + it("scrolls if the target is off the bottom of the screen", () => { + if (html) { + html.scrollTop = 100; + } + const { result } = renderHook(() => useScrollOnRender()); + targetNode.getBoundingClientRect = () => ({ y: 1000 } as DOMRect); + result.current(targetNode); + expect(scrollToSpy).toHaveBeenCalledWith({ + top: 1000, + left: 0, + behavior: "smooth", }); + }); - it("scrolls if the target is partially off the bottom of the screen", () => { - if (html) { - html.scrollTop = 100; - } - const { result } = renderHook(() => useScrollOnRender()); - targetNode.getBoundingClientRect = () => - ({ height: 400, y: 400 } as DOMRect); - result.current(targetNode); - expect(scrollToSpy).toHaveBeenCalledWith({ - top: 400, - left: 0, - behavior: "smooth", - }); + it("scrolls if the target is off the top of the screen", () => { + if (html) { + html.scrollTop = 1000; + } + const { result } = renderHook(() => useScrollOnRender()); + targetNode.getBoundingClientRect = () => ({ y: 10 } as DOMRect); + result.current(targetNode); + expect(scrollToSpy).toHaveBeenCalledWith({ + top: 10, + left: 0, + behavior: "smooth", }); }); - describe("useCycled", () => { - it("can handle the initial state", () => { - const onCycled = vi.fn(); - const { result } = renderHook(() => useCycled(false, onCycled)); - const [hasCycled] = result.current; - expect(hasCycled).toBe(false); - expect(onCycled).not.toHaveBeenCalled(); + it("scrolls if the target is partially off the bottom of the screen", () => { + if (html) { + html.scrollTop = 100; + } + const { result } = renderHook(() => useScrollOnRender()); + targetNode.getBoundingClientRect = () => + ({ height: 400, y: 400 } as DOMRect); + result.current(targetNode); + expect(scrollToSpy).toHaveBeenCalledWith({ + top: 400, + left: 0, + behavior: "smooth", }); + }); +}); - it("can handle rerenders when the value has not cycled", () => { - const onCycled = vi.fn(); - const { result, rerender } = renderHook( - ({ state }) => useCycled(state, onCycled), - { - initialProps: { state: false }, - } - ); - rerender({ state: false }); - const [hasCycled] = result.current; - expect(hasCycled).toBe(false); - expect(onCycled).not.toHaveBeenCalled(); - }); +describe("useCycled", () => { + it("can handle the initial state", () => { + const onCycled = vi.fn(); + const { result } = renderHook(() => useCycled(false, onCycled)); + const [hasCycled] = result.current; + expect(hasCycled).toBe(false); + expect(onCycled).not.toHaveBeenCalled(); + }); - it("can handle rerenders when the value has cycled", () => { - const onCycled = vi.fn(); - const { result, rerender } = renderHook( - ({ state }) => useCycled(state, onCycled), - { - initialProps: { state: false }, - } - ); - rerender({ state: true }); - const [hasCycled] = result.current; - expect(hasCycled).toBe(true); - expect(onCycled).toHaveBeenCalled(); - }); + it("can handle rerenders when the value has not cycled", () => { + const onCycled = vi.fn(); + const { result, rerender } = renderHook( + ({ state }) => useCycled(state, onCycled), + { + initialProps: { state: false }, + } + ); + rerender({ state: false }); + const [hasCycled] = result.current; + expect(hasCycled).toBe(false); + expect(onCycled).not.toHaveBeenCalled(); + }); - it("can reset the cycle", async () => { - const onCycled = vi.fn(); - const { result, rerender } = renderHook( - ({ state }) => useCycled(state, onCycled), - { - initialProps: { state: false }, - } - ); - rerender({ state: true }); - let [hasCycled, resetCycle] = result.current; - expect(hasCycled).toBe(true); - expect(onCycled).toHaveBeenCalledTimes(1); - resetCycle(); - await waitFor(() => { - [hasCycled, resetCycle] = result.current; - return expect(hasCycled).toBe(false); - }); - // The onCycle function should not get called when it resets. - expect(onCycled).toHaveBeenCalledTimes(1); - }); + it("can handle rerenders when the value has cycled", () => { + const onCycled = vi.fn(); + const { result, rerender } = renderHook( + ({ state }) => useCycled(state, onCycled), + { + initialProps: { state: false }, + } + ); + rerender({ state: true }); + const [hasCycled] = result.current; + expect(hasCycled).toBe(true); + expect(onCycled).toHaveBeenCalled(); + }); - it("can handle values that have cycled after a reset", async () => { - const onCycled = vi.fn(); - const { result, rerender } = renderHook( - ({ state }) => useCycled(state, onCycled), - { - initialProps: { state: false }, - } - ); - // Cycle the value to true: - rerender({ state: true }); - let [hasCycled, resetCycle] = result.current; - expect(hasCycled).toBe(true); - // Reset to false: - resetCycle(); - rerender({ state: false }); - await waitFor(() => { - [hasCycled, resetCycle] = result.current; - return expect(hasCycled).toBe(false); - }); - // Cycle the value back to true: - rerender({ state: true }); + it("can reset the cycle", async () => { + const onCycled = vi.fn(); + const { result, rerender } = renderHook( + ({ state }) => useCycled(state, onCycled), + { + initialProps: { state: false }, + } + ); + rerender({ state: true }); + let [hasCycled, resetCycle] = result.current; + expect(hasCycled).toBe(true); + expect(onCycled).toHaveBeenCalledTimes(1); + resetCycle(); + await waitFor(() => { [hasCycled, resetCycle] = result.current; - expect(hasCycled).toBe(true); - expect(onCycled).toHaveBeenCalledTimes(2); + return expect(hasCycled).toBe(false); }); + // The onCycle function should not get called when it resets. + expect(onCycled).toHaveBeenCalledTimes(1); }); - describe("useProcessing", () => { - it("handles whether processing has completed", () => { - const onComplete = vi.fn(); - const onError = vi.fn(); - // Start with a count of 0 - const { rerender, result } = renderHook( - ({ processingCount }) => - useProcessing({ onComplete, onError, processingCount }), - { initialProps: { processingCount: 0 } } - ); - expect(onComplete).not.toHaveBeenCalled(); - expect(onError).not.toHaveBeenCalled(); - expect(result.current).toBe(false); - - // Start processing with a count of 1 - processing should not be complete. - rerender({ processingCount: 1 }); - expect(onComplete).not.toHaveBeenCalled(); - expect(onError).not.toHaveBeenCalled(); - expect(result.current).toBe(false); - - // Count down to 0 - processing should be complete and onComplete should run. - rerender({ processingCount: 0 }); - expect(onComplete).toHaveBeenCalled(); - expect(onError).not.toHaveBeenCalled(); - expect(result.current).toBe(true); + it("can handle values that have cycled after a reset", async () => { + const onCycled = vi.fn(); + const { result, rerender } = renderHook( + ({ state }) => useCycled(state, onCycled), + { + initialProps: { state: false }, + } + ); + // Cycle the value to true: + rerender({ state: true }); + let [hasCycled, resetCycle] = result.current; + expect(hasCycled).toBe(true); + // Reset to false: + resetCycle(); + rerender({ state: false }); + await waitFor(() => { + [hasCycled, resetCycle] = result.current; + return expect(hasCycled).toBe(false); }); + // Cycle the value back to true: + rerender({ state: true }); + [hasCycled, resetCycle] = result.current; + expect(hasCycled).toBe(true); + expect(onCycled).toHaveBeenCalledTimes(2); + }); +}); - it("handles errors occurring while processing", () => { - const onComplete = vi.fn(); - const onError = vi.fn(); - // Start with a count of 0 - const { rerender, result } = renderHook( - ({ hasErrors, processingCount }) => - useProcessing({ hasErrors, onComplete, onError, processingCount }), - { initialProps: { hasErrors: false, processingCount: 0 } } - ); - expect(onComplete).not.toHaveBeenCalled(); - expect(onError).not.toHaveBeenCalled(); - expect(result.current).toBe(false); - - // Start processing with a count of 1 - processing should not be complete. - rerender({ hasErrors: false, processingCount: 1 }); - expect(onComplete).not.toHaveBeenCalled(); - expect(onError).not.toHaveBeenCalled(); - expect(result.current).toBe(false); - - // Count down to 0 - processing should not be complete, onComplete should - // not run but onError should have run. - rerender({ hasErrors: true, processingCount: 0 }); - expect(onComplete).not.toHaveBeenCalled(); - expect(onError).toHaveBeenCalled(); - expect(result.current).toBe(false); - }); +describe("useProcessing", () => { + it("handles whether processing has completed", () => { + const onComplete = vi.fn(); + const onError = vi.fn(); + // Start with a count of 0 + const { rerender, result } = renderHook( + ({ processingCount }) => + useProcessing({ onComplete, onError, processingCount }), + { initialProps: { processingCount: 0 } } + ); + expect(onComplete).not.toHaveBeenCalled(); + expect(onError).not.toHaveBeenCalled(); + expect(result.current).toBe(false); + + // Start processing with a count of 1 - processing should not be complete. + rerender({ processingCount: 1 }); + expect(onComplete).not.toHaveBeenCalled(); + expect(onError).not.toHaveBeenCalled(); + expect(result.current).toBe(false); + + // Count down to 0 - processing should be complete and onComplete should run. + rerender({ processingCount: 0 }); + expect(onComplete).toHaveBeenCalled(); + expect(onError).not.toHaveBeenCalled(); + expect(result.current).toBe(true); }); - describe("getId", () => { - it("generates the id on first render", () => { - const { result, rerender } = renderHook(() => useId()); - expect(result.current).toBeTruthy(); - const previousResult = result; - rerender(); - expect(result.current).toEqual(previousResult.current); - }); + it("handles errors occurring while processing", () => { + const onComplete = vi.fn(); + const onError = vi.fn(); + // Start with a count of 0 + const { rerender, result } = renderHook( + ({ hasErrors, processingCount }) => + useProcessing({ hasErrors, onComplete, onError, processingCount }), + { initialProps: { hasErrors: false, processingCount: 0 } } + ); + expect(onComplete).not.toHaveBeenCalled(); + expect(onError).not.toHaveBeenCalled(); + expect(result.current).toBe(false); + + // Start processing with a count of 1 - processing should not be complete. + rerender({ hasErrors: false, processingCount: 1 }); + expect(onComplete).not.toHaveBeenCalled(); + expect(onError).not.toHaveBeenCalled(); + expect(result.current).toBe(false); + + // Count down to 0 - processing should not be complete, onComplete should + // not run but onError should have run. + rerender({ hasErrors: true, processingCount: 0 }); + expect(onComplete).not.toHaveBeenCalled(); + expect(onError).toHaveBeenCalled(); + expect(result.current).toBe(false); }); +}); - describe("useScrollToTop", () => { - it("scrolls to the top of the page on pathname change", () => { - const scrollToSpy = vi.fn(); - global.scrollTo = scrollToSpy; - const { rerender } = renderHook(() => useScrollToTop()); +describe("getId", () => { + it("generates the id on first render", () => { + const { result, rerender } = renderHook(() => useId()); + expect(result.current).toBeTruthy(); + const previousResult = result; + rerender(); + expect(result.current).toEqual(previousResult.current); + }); +}); - expect(scrollToSpy).toHaveBeenCalledWith(0, 0); - expect(scrollToSpy).toHaveBeenCalledTimes(1); +describe("useScrollToTop", () => { + it("scrolls to the top of the page on pathname change", () => { + const scrollToSpy = vi.fn(); + global.scrollTo = scrollToSpy; + const { rerender } = renderHook(() => useScrollToTop()); - mockUseLocationValue.pathname = "/new-pathname"; - rerender(); + expect(scrollToSpy).toHaveBeenCalledWith(0, 0); + expect(scrollToSpy).toHaveBeenCalledTimes(1); - expect(scrollToSpy).toHaveBeenCalledTimes(2); - }); + mockUseLocationValue.pathname = "/new-pathname"; + rerender(); + + expect(scrollToSpy).toHaveBeenCalledTimes(2); + }); - it("does not scroll to the top of the page if pathname stays the same", () => { - const scrollToSpy = vi.fn(); - global.scrollTo = scrollToSpy; - const { rerender } = renderHook(() => useScrollToTop()); + it("does not scroll to the top of the page if pathname stays the same", () => { + const scrollToSpy = vi.fn(); + global.scrollTo = scrollToSpy; + const { rerender } = renderHook(() => useScrollToTop()); - expect(scrollToSpy).toHaveBeenCalledWith(0, 0); - expect(scrollToSpy).toHaveBeenCalledTimes(1); + expect(scrollToSpy).toHaveBeenCalledWith(0, 0); + expect(scrollToSpy).toHaveBeenCalledTimes(1); - rerender(); + rerender(); - expect(scrollToSpy).toHaveBeenCalledTimes(1); - }); + expect(scrollToSpy).toHaveBeenCalledTimes(1); }); +}); - describe("usePreviousPersistent", () => { - it("should return null on initial render", () => { - const { result } = renderHook(() => usePreviousPersistent({ a: "b" })); +describe("usePreviousPersistent", () => { + it("should return null on initial render", () => { + const { result } = renderHook(() => usePreviousPersistent({ a: "b" })); - expect(result.current).toBeNull(); - }); + expect(result.current).toBeNull(); + }); - it("persists previous values on re-render", () => { - const { rerender, result } = renderHook( - (state) => usePreviousPersistent(state), - { - initialProps: 1, - } - ); - - rerender(2); - expect(result.current).toEqual(1); - rerender(3); - expect(result.current).toEqual(2); - }); + it("persists previous values on re-render", () => { + const { rerender, result } = renderHook( + (state) => usePreviousPersistent(state), + { + initialProps: 1, + } + ); + + rerender(2); + expect(result.current).toEqual(1); + rerender(3); + expect(result.current).toEqual(2); }); }); diff --git a/src/app/machines/views/MachineDetails/MachineDetails.test.tsx b/src/app/machines/views/MachineDetails/MachineDetails.test.tsx index ae219f2045..9493273a90 100644 --- a/src/app/machines/views/MachineDetails/MachineDetails.test.tsx +++ b/src/app/machines/views/MachineDetails/MachineDetails.test.tsx @@ -109,14 +109,16 @@ describe("MachineDetails", () => { title: "configuration", }, ].forEach(({ component, path, title }) => { - it(`Displays: ${component} at: ${path}`, () => { + it(`Displays: ${component} at: ${path}`, async () => { renderWithBrowserRouter(, { route: path, state, routePattern: `${urls.machines.machine.index(null)}/*`, }); - expect(document.title).toBe( - `${state.machine.items[0].fqdn} ${title} | MAAS` + await waitFor(() => + expect(document.title).toBe( + `${state.machine.items[0].fqdn} ${title} | MAAS` + ) ); }); }); diff --git a/src/testing/constants.ts b/src/testing/constants.ts new file mode 100644 index 0000000000..cb8f0d8186 --- /dev/null +++ b/src/testing/constants.ts @@ -0,0 +1 @@ +export const LONG_TIMEOUT = 10000; diff --git a/yarn.lock b/yarn.lock index 1cffead766..328c4499f2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4782,9 +4782,9 @@ "@types/chai" "*" "@types/chai@*", "@types/chai@^4.3.5": - version "4.3.10" - resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.3.10.tgz#2ad2959d1767edee5b0e4efb1a0cd2b500747317" - integrity sha512-of+ICnbqjmFCiixUnqRulbylyXQrPqIGf/B3Jax1wIF3DvSheysQxAWvqHhZiW3IQrycvokcLcFQlveGp+vyNg== + version "4.3.11" + resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.3.11.tgz#e95050bf79a932cb7305dd130254ccdf9bde671c" + integrity sha512-qQR1dr2rGIHYlJulmr8Ioq3De0Le9E4MJ5AiaeAETJJpndT1uUNHsGFK3L/UIu+rbkQSdj8J/w2bCsBZc/Y5fQ== "@types/classnames@2.3.0": version "2.3.0" @@ -5594,9 +5594,9 @@ acorn-walk@^7.2.0: integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA== acorn-walk@^8.2.0: - version "8.3.0" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.0.tgz#2097665af50fd0cf7a2dfccd2b9368964e66540f" - integrity sha512-FS7hV565M5l1R08MXqo8odwMTB02C2UqzB17RVgu9EyuYFBqJZ3/ZY97sQD5FewVu1UyDFc1yztUDrAwT0EypA== + version "8.3.2" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.2.tgz#7703af9415f1b6db9315d6895503862e231d34aa" + integrity sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A== acorn@^7.4.1: version "7.4.1" @@ -5608,6 +5608,11 @@ acorn@^8.10.0: resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.2.tgz#ca0d78b51895be5390a5903c5b3bdcdaf78ae40b" integrity sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w== +acorn@^8.11.3: + version "8.11.3" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.3.tgz#71e0b14e13a4ec160724b38fb7b0f233b1b81d7a" + integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg== + acorn@^8.5.0, acorn@^8.7.1: version "8.7.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.1.tgz#0197122c843d1bf6d0a5e83220a788f278f63c30" @@ -7676,7 +7681,7 @@ esbuild-register@^3.4.0: dependencies: debug "^4.3.4" -esbuild@^0.18.0, esbuild@^0.18.10: +esbuild@^0.18.0: version "0.18.20" resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.18.20.tgz#4709f5a34801b43b799ab7d6d82f7284a9b7a7a6" integrity sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA== @@ -10444,7 +10449,7 @@ mkdirp@^1.0.3: resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== -mlly@^1.2.0, mlly@^1.4.0: +mlly@^1.2.0: version "1.4.2" resolved "https://registry.yarnpkg.com/mlly/-/mlly-1.4.2.tgz#7cf406aa319ff6563d25da6b36610a93f2a8007e" integrity sha512-i/Ykufi2t1EZ6NaPLdfnZk2AX8cs0d+mTzVKuPfqPKPatxLApaBoxJQ9x1/uckXtrS/U5oisPMDkNs0yQTaBRg== @@ -10454,6 +10459,16 @@ mlly@^1.2.0, mlly@^1.4.0: pkg-types "^1.0.3" ufo "^1.3.0" +mlly@^1.4.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/mlly/-/mlly-1.5.0.tgz#8428a4617d54cc083d3009030ac79739a0e5447a" + integrity sha512-NPVQvAY1xr1QoVeG0cy8yUYC7FQcOx6evl/RjT1wL5FvzPnzOysoqB/jmx/DhssT2dYa8nxECLAaFI/+gVLhDQ== + dependencies: + acorn "^8.11.3" + pathe "^1.1.2" + pkg-types "^1.0.3" + ufo "^1.3.2" + mock-socket@9.2.1: version "9.2.1" resolved "https://registry.yarnpkg.com/mock-socket/-/mock-socket-9.2.1.tgz#cc9c0810aa4d0afe02d721dcb2b7e657c00e2282" @@ -11026,6 +11041,11 @@ pathe@^1.1.0, pathe@^1.1.1: resolved "https://registry.yarnpkg.com/pathe/-/pathe-1.1.1.tgz#1dd31d382b974ba69809adc9a7a347e65d84829a" integrity sha512-d+RQGp0MAYTIaDBIMmOfMwz3E+LOZnxx1HZd5R18mmCZY0QBlK0LDZfPc8FW8Ed2DlvsuE6PRjroDY+wg4+j/Q== +pathe@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/pathe/-/pathe-1.1.2.tgz#6c4cb47a945692e48a1ddd6e4094d170516437ec" + integrity sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ== + pathval@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.1.tgz#8534e77a77ce7ac5a2512ea21e0fdb8fcf6c3d8d" @@ -11228,7 +11248,7 @@ postcss-value-parser@^4.2.0: resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== -postcss@^8.4.21, postcss@^8.4.27, postcss@^8.4.32: +postcss@^8.4.21, postcss@^8.4.32: version "8.4.33" resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.33.tgz#1378e859c9f69bf6f638b990a0212f43e2aaa742" integrity sha512-Kkpbhhdjw2qQs2O2DGX+8m5OVqEcbB9HRBvuYM9pgrjEFUg30A9LmXNlTAUj4S9kgtGyrMbTzVjH7E+s5Re2yg== @@ -12117,13 +12137,6 @@ rollup@^2.77.2: optionalDependencies: fsevents "~2.3.2" -rollup@^3.27.1: - version "3.29.4" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-3.29.4.tgz#4d70c0f9834146df8705bfb69a9a19c9e1109981" - integrity sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw== - optionalDependencies: - fsevents "~2.3.2" - rollup@^4.2.0: version "4.8.0" resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.8.0.tgz#365c34e85f1ed034de974dab934c1663cc69b754" @@ -12580,9 +12593,9 @@ statuses@2.0.1: integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== std-env@^3.3.3: - version "3.4.3" - resolved "https://registry.yarnpkg.com/std-env/-/std-env-3.4.3.tgz#326f11db518db751c83fd58574f449b7c3060910" - integrity sha512-f9aPhy8fYBuMN+sNfakZV18U39PbalgjXG3lLB9WkaYTxijru61wb57V9wxxNthXM5Sd88ETBWi29qLAsHO52Q== + version "3.7.0" + resolved "https://registry.yarnpkg.com/std-env/-/std-env-3.7.0.tgz#c9f7386ced6ecf13360b6c6c55b8aaa4ef7481d2" + integrity sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg== stop-iteration-iterator@^1.0.0: version "1.0.0" @@ -12958,9 +12971,9 @@ tiny-warning@^1.0.0, tiny-warning@^1.0.2: integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA== tinybench@^2.5.0: - version "2.5.1" - resolved "https://registry.yarnpkg.com/tinybench/-/tinybench-2.5.1.tgz#3408f6552125e53a5a48adee31261686fd71587e" - integrity sha512-65NKvSuAVDP/n4CqH+a9w2kTlLReS9vhsAP06MWx+/89nMinJyB2icyl58RIcqCmIggpojIGeuJGhjU1aGMBSg== + version "2.6.0" + resolved "https://registry.yarnpkg.com/tinybench/-/tinybench-2.6.0.tgz#1423284ee22de07c91b3752c048d2764714b341b" + integrity sha512-N8hW3PG/3aOoZAN5V/NSAEDz0ZixDSSt5b/a05iqtpgfLWMSVuCo7w0k2vVvEjdrIoeGqZzweX2WlyioNIHchA== tinypool@^0.7.0: version "0.7.0" @@ -13265,6 +13278,11 @@ ufo@^1.3.0: resolved "https://registry.yarnpkg.com/ufo/-/ufo-1.3.1.tgz#e085842f4627c41d4c1b60ebea1f75cdab4ce86b" integrity sha512-uY/99gMLIOlJPwATcMVYfqDSxUR9//AUcgZMzwfSTJPDKzA1S8mX4VLqa+fiAtveraQUBCz4FFcwVZBGbwBXIw== +ufo@^1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/ufo/-/ufo-1.3.2.tgz#c7d719d0628a1c80c006d2240e0d169f6e3c0496" + integrity sha512-o+ORpgGwaYQXgqGDwd+hkS4PuZ3QnmqMMxRuajK/a38L6fTpcE5GPIfrf+L/KemFzfUpeUQc1rRS1iDBozvnFA== + uglify-js@^3.1.4: version "3.17.4" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.17.4.tgz#61678cf5fa3f5b7eb789bb345df29afb8257c22c" @@ -13578,15 +13596,15 @@ vite@5.0.12: fsevents "~2.3.3" "vite@^3.0.0 || ^4.0.0 || ^5.0.0-0", "vite@^3.1.0 || ^4.0.0 || ^5.0.0-0": - version "4.5.0" - resolved "https://registry.yarnpkg.com/vite/-/vite-4.5.0.tgz#ec406295b4167ac3bc23e26f9c8ff559287cff26" - integrity sha512-ulr8rNLA6rkyFAlVWw2q5YJ91v098AFQ2R0PRFwPzREXOUJQPtFUG0t+/ZikhaOCDqFoDhN6/v8Sq0o4araFAw== + version "5.0.12" + resolved "https://registry.yarnpkg.com/vite/-/vite-5.0.12.tgz#8a2ffd4da36c132aec4adafe05d7adde38333c47" + integrity sha512-4hsnEkG3q0N4Tzf1+t6NdN9dg/L3BM+q8SWgbSPnJvrgH2kgdyzfVJwbR1ic69/4uMJJ/3dqDZZE5/WwqW8U1w== dependencies: - esbuild "^0.18.10" - postcss "^8.4.27" - rollup "^3.27.1" + esbuild "^0.19.3" + postcss "^8.4.32" + rollup "^4.2.0" optionalDependencies: - fsevents "~2.3.2" + fsevents "~2.3.3" vitest-fetch-mock@0.2.2: version "0.2.2"