Skip to content

Commit 1ab6f03

Browse files
committed
refactor: remove reliance on internal React Router state property
1 parent dcc89dc commit 1ab6f03

File tree

1 file changed

+31
-23
lines changed

1 file changed

+31
-23
lines changed

site/src/testHelpers/hooks.tsx

Lines changed: 31 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {
55
renderHook,
66
act,
77
} from "@testing-library/react";
8-
import { type ReactNode, useState } from "react";
8+
import { type ReactNode, useReducer, FC, PropsWithChildren } from "react";
99
import { QueryClient } from "react-query";
1010
import { AppProviders } from "App";
1111
import { RequireAuth } from "contexts/auth/RequireAuth";
@@ -17,6 +17,7 @@ import {
1717
type Location,
1818
createMemoryRouter,
1919
RouterProvider,
20+
useLocation,
2021
} from "react-router-dom";
2122

2223
export type RouterLocationSnapshot<TLocationState = unknown> = Readonly<{
@@ -122,34 +123,42 @@ export async function renderHookWithAuth<Result, Props>(
122123
* the snapshot we grabbed (even if the inner values are the same, the
123124
* reference values will be different), resolving that via a promise
124125
*/
125-
// Easy to miss - definite assignment via !
126-
let forceChildRerender!: () => void;
126+
// Easy to miss - definite assignments via !
127+
let forceRenderHookChildrenUpdate!: () => void;
128+
let escapedLocation!: Location;
127129
let currentRenderHookChildren: ReactNode = undefined;
128130

129-
const RenderHookEscapeHatch = () => {
130-
const [, setThrowawayRenderValue] = useState(false);
131-
forceChildRerender = () => {
132-
act(() => setThrowawayRenderValue((current) => !current));
133-
};
131+
const LocationLeaker: FC<PropsWithChildren> = ({ children }) => {
132+
const location = useLocation();
133+
escapedLocation = location;
134+
return <>{children}</>;
135+
};
134136

135-
return <>{currentRenderHookChildren}</>;
137+
const InitialRoute: FC = () => {
138+
const [, forceInternalRerender] = useReducer((b: boolean) => !b, false);
139+
forceRenderHookChildrenUpdate = () => act(() => forceInternalRerender());
140+
return <LocationLeaker>{currentRenderHookChildren}</LocationLeaker>;
136141
};
137142

143+
const wrappedExtraRoutes = extraRoutes.map((route) => ({
144+
...route,
145+
element: <LocationLeaker>{route.element}</LocationLeaker>,
146+
}));
147+
148+
const wrappedNonAuthRoutes = nonAuthenticatedRoutes.map((route) => ({
149+
...route,
150+
element: <LocationLeaker>{route.element}</LocationLeaker>,
151+
}));
152+
138153
const router = createMemoryRouter(
139154
[
140155
{
141156
element: <RequireAuth />,
142-
children: [
143-
{ path, element: <RenderHookEscapeHatch /> },
144-
...extraRoutes,
145-
],
157+
children: [{ path, element: <InitialRoute /> }, ...wrappedExtraRoutes],
146158
},
147-
...nonAuthenticatedRoutes,
159+
...wrappedNonAuthRoutes,
148160
],
149-
{
150-
initialEntries: [route],
151-
initialIndex: 0,
152-
},
161+
{ initialEntries: [route], initialIndex: 0 },
153162
);
154163

155164
const queryClient = createTestQueryClient();
@@ -182,15 +191,14 @@ export async function renderHookWithAuth<Result, Props>(
182191
rerender: (newProps) => {
183192
const currentValue = result.current;
184193
rerender(newProps);
185-
forceChildRerender();
194+
forceRenderHookChildrenUpdate();
186195
return waitFor(() => expect(result.current).not.toBe(currentValue));
187196
},
188197
getLocationSnapshot: () => {
189-
const location = router.state.location;
190198
return {
191-
pathname: location.pathname,
192-
search: new URLSearchParams(location.search),
193-
state: location.state,
199+
pathname: escapedLocation.pathname,
200+
search: new URLSearchParams(escapedLocation.search),
201+
state: escapedLocation.state,
194202
};
195203
},
196204
} as const;

0 commit comments

Comments
 (0)