5
5
renderHook ,
6
6
act ,
7
7
} from "@testing-library/react" ;
8
- import { type ReactNode , useState } from "react" ;
8
+ import { type ReactNode , useReducer , FC , PropsWithChildren } from "react" ;
9
9
import { QueryClient } from "react-query" ;
10
10
import { AppProviders } from "App" ;
11
11
import { RequireAuth } from "contexts/auth/RequireAuth" ;
@@ -17,6 +17,7 @@ import {
17
17
type Location ,
18
18
createMemoryRouter ,
19
19
RouterProvider ,
20
+ useLocation ,
20
21
} from "react-router-dom" ;
21
22
22
23
export type RouterLocationSnapshot < TLocationState = unknown > = Readonly < {
@@ -122,34 +123,42 @@ export async function renderHookWithAuth<Result, Props>(
122
123
* the snapshot we grabbed (even if the inner values are the same, the
123
124
* reference values will be different), resolving that via a promise
124
125
*/
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 ;
127
129
let currentRenderHookChildren : ReactNode = undefined ;
128
130
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
+ } ;
134
136
135
- return < > { currentRenderHookChildren } </ > ;
137
+ const InitialRoute : FC = ( ) => {
138
+ const [ , forceInternalRerender ] = useReducer ( ( b : boolean ) => ! b , false ) ;
139
+ forceRenderHookChildrenUpdate = ( ) => act ( ( ) => forceInternalRerender ( ) ) ;
140
+ return < LocationLeaker > { currentRenderHookChildren } </ LocationLeaker > ;
136
141
} ;
137
142
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
+
138
153
const router = createMemoryRouter (
139
154
[
140
155
{
141
156
element : < RequireAuth /> ,
142
- children : [
143
- { path, element : < RenderHookEscapeHatch /> } ,
144
- ...extraRoutes ,
145
- ] ,
157
+ children : [ { path, element : < InitialRoute /> } , ...wrappedExtraRoutes ] ,
146
158
} ,
147
- ...nonAuthenticatedRoutes ,
159
+ ...wrappedNonAuthRoutes ,
148
160
] ,
149
- {
150
- initialEntries : [ route ] ,
151
- initialIndex : 0 ,
152
- } ,
161
+ { initialEntries : [ route ] , initialIndex : 0 } ,
153
162
) ;
154
163
155
164
const queryClient = createTestQueryClient ( ) ;
@@ -182,15 +191,14 @@ export async function renderHookWithAuth<Result, Props>(
182
191
rerender : ( newProps ) => {
183
192
const currentValue = result . current ;
184
193
rerender ( newProps ) ;
185
- forceChildRerender ( ) ;
194
+ forceRenderHookChildrenUpdate ( ) ;
186
195
return waitFor ( ( ) => expect ( result . current ) . not . toBe ( currentValue ) ) ;
187
196
} ,
188
197
getLocationSnapshot : ( ) => {
189
- const location = router . state . location ;
190
198
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 ,
194
202
} ;
195
203
} ,
196
204
} as const ;
0 commit comments