1- import { expect , test } from 'vitest'
2- import { fireEvent , render , screen } from '@testing-library/react'
1+ import { afterEach , describe , expect , test } from 'vitest'
2+ import { act , cleanup , fireEvent , render , screen } from '@testing-library/react'
3+ import { createMemoryHistory } from '@tanstack/history'
34import {
45 Link ,
56 Outlet ,
89 createRoute ,
910 createRouter ,
1011 isMatch ,
12+ useMatchRoute ,
1113 useMatches ,
1214} from '../src'
1315
@@ -130,6 +132,7 @@ test('should show pendingComponent of root route', async () => {
130132 } ,
131133 component : ( ) => < div data-testId = "root-content" /> ,
132134 } )
135+
133136 const router = createRouter ( {
134137 routeTree : root ,
135138 defaultPendingMs : 0 ,
@@ -141,3 +144,213 @@ test('should show pendingComponent of root route', async () => {
141144 expect ( await rendered . findByTestId ( 'root-pending' ) ) . toBeInTheDocument ( )
142145 expect ( await rendered . findByTestId ( 'root-content' ) ) . toBeInTheDocument ( )
143146} )
147+
148+ describe ( 'matching on different param types' , ( ) => {
149+ const testCases = [
150+ {
151+ name : 'param with braces' ,
152+ path : '/$id' ,
153+ nav : '/1' ,
154+ params : { id : '1' } ,
155+ matchParams : { id : '1' } ,
156+ } ,
157+ {
158+ name : 'param without braces' ,
159+ path : '/{$id}' ,
160+ nav : '/2' ,
161+ params : { id : '2' } ,
162+ matchParams : { id : '2' } ,
163+ } ,
164+ {
165+ name : 'param with prefix' ,
166+ path : '/prefix-{$id}' ,
167+ nav : '/prefix-3' ,
168+ params : { id : '3' } ,
169+ matchParams : { id : '3' } ,
170+ } ,
171+ {
172+ name : 'param with suffix' ,
173+ path : '/{$id}-suffix' ,
174+ nav : '/4-suffix' ,
175+ params : { id : '4' } ,
176+ matchParams : { id : '4' } ,
177+ } ,
178+ {
179+ name : 'param with prefix and suffix' ,
180+ path : '/prefix-{$id}-suffix' ,
181+ nav : '/prefix-5-suffix' ,
182+ params : { id : '5' } ,
183+ matchParams : { id : '5' } ,
184+ } ,
185+ {
186+ name : 'wildcard with no braces' ,
187+ path : '/abc/$' ,
188+ nav : '/abc/6' ,
189+ params : { '*' : '6' , _splat : '6' } ,
190+ matchParams : { '*' : '6' , _splat : '6' } ,
191+ } ,
192+ {
193+ name : 'wildcard with braces' ,
194+ path : '/abc/{$}' ,
195+ nav : '/abc/7' ,
196+ params : { '*' : '7' , _splat : '7' } ,
197+ matchParams : { '*' : '7' , _splat : '7' } ,
198+ } ,
199+ {
200+ name : 'wildcard with prefix' ,
201+ path : '/abc/prefix{$}' ,
202+ nav : '/abc/prefix/8' ,
203+ params : { '*' : '/8' , _splat : '/8' } ,
204+ matchParams : { '*' : '/8' , _splat : '/8' } ,
205+ } ,
206+ {
207+ name : 'wildcard with suffix' ,
208+ path : '/abc/{$}suffix' ,
209+ nav : '/abc/9/suffix' ,
210+ params : { _splat : '9/' , '*' : '9/' } ,
211+ matchParams : { _splat : '9/' , '*' : '9/' } ,
212+ } ,
213+ {
214+ name : 'optional param with no prefix/suffix and value' ,
215+ path : '/abc/{-$id}/def' ,
216+ nav : '/abc/10/def' ,
217+ params : { id : '10' } ,
218+ matchParams : { id : '10' } ,
219+ } ,
220+ {
221+ name : 'optional param with no prefix/suffix and requiredParam and no value' ,
222+ path : '/abc/{-$id}/$foo/def' ,
223+ nav : '/abc/bar/def' ,
224+ params : { foo : 'bar' } ,
225+ matchParams : { foo : 'bar' } ,
226+ } ,
227+ {
228+ name : 'optional param with no prefix/suffix and requiredParam and value' ,
229+ path : '/abc/{-$id}/$foo/def' ,
230+ nav : '/abc/10/bar/def' ,
231+ params : { id : '10' , foo : 'bar' } ,
232+ matchParams : { id : '10' , foo : 'bar' } ,
233+ } ,
234+ {
235+ name : 'optional param with no prefix/suffix and no value' ,
236+ path : '/abc/{-$id}/def' ,
237+ nav : '/abc/def' ,
238+ params : { } ,
239+ matchParams : { } ,
240+ } ,
241+ {
242+ name : 'multiple optional params with no prefix/suffix and no value' ,
243+ path : '/{-$a}/{-$b}/{-$c}' ,
244+ nav : '/' ,
245+ params : { } ,
246+ matchParams : { } ,
247+ } ,
248+ {
249+ name : 'multiple optional params with no prefix/suffix and values' ,
250+ path : '/{-$a}/{-$b}/{-$c}' ,
251+ nav : '/foo/bar/qux' ,
252+ params : { a : 'foo' , b : 'bar' , c : 'qux' } ,
253+ matchParams : { a : 'foo' , b : 'bar' , c : 'qux' } ,
254+ } ,
255+ {
256+ name : 'multiple optional params with no prefix/suffix and mixed values' ,
257+ path : '/{-$a}/{-$b}/{-$c}' ,
258+ nav : '/foo/qux' ,
259+ params : { a : 'foo' , b : 'qux' } ,
260+ matchParams : { a : 'foo' , b : 'qux' } ,
261+ } ,
262+ {
263+ name : 'optional param with prefix and value' ,
264+ path : '/optional-{-$id}' ,
265+ nav : '/optional-12' ,
266+ params : { id : '12' } ,
267+ matchParams : { id : '12' } ,
268+ } ,
269+ {
270+ name : 'optional param with prefix and no value' ,
271+ path : '/optional-{-$id}' ,
272+ nav : '/optional-' ,
273+ params : { } ,
274+ matchParams : { id : '' } ,
275+ } ,
276+ {
277+ name : 'optional param with suffix and value' ,
278+ path : '/{-$id}-optional' ,
279+ nav : '/13-optional' ,
280+ params : { id : '13' } ,
281+ matchParams : { id : '13' } ,
282+ } ,
283+ {
284+ name : 'optional param with suffix and no value' ,
285+ path : '/{-$id}-optional' ,
286+ nav : '/-optional' ,
287+ params : { } ,
288+ matchParams : { id : '' } ,
289+ } ,
290+ {
291+ name : 'optional param with required param, prefix, suffix, wildcard and no value' ,
292+ path : `/$foo/a{-$id}-optional/$` ,
293+ nav : '/bar/a-optional/qux' ,
294+ params : { foo : 'bar' , id : '' , _splat : 'qux' , '*' : 'qux' } ,
295+ matchParams : { foo : 'bar' , id : '' , _splat : 'qux' , '*' : 'qux' } ,
296+ } ,
297+ {
298+ name : 'optional param with required param, prefix, suffix, wildcard and value' ,
299+ path : `/$foo/a{-$id}-optional/$` ,
300+ nav : '/bar/a14-optional/qux' ,
301+ params : { foo : 'bar' , id : '14' , _splat : 'qux' , '*' : 'qux' } ,
302+ matchParams : { foo : 'bar' , id : '14' , _splat : 'qux' , '*' : 'qux' } ,
303+ } ,
304+ ]
305+
306+ afterEach ( ( ) => cleanup ( ) )
307+ test . each ( testCases ) (
308+ '$name' ,
309+ async ( { name, path, params, matchParams, nav } ) => {
310+ const rootRoute = createRootRoute ( )
311+
312+ const Route = createRoute ( {
313+ getParentRoute : ( ) => rootRoute ,
314+ path,
315+ component : RouteComponent ,
316+ } )
317+
318+ function RouteComponent ( ) {
319+ const routeParams = Route . useParams ( )
320+ const matchRoute = useMatchRoute ( )
321+ const matchRouteMatch = matchRoute ( {
322+ to : path ,
323+ } )
324+
325+ return (
326+ < div >
327+ < h1 data-testid = "heading" > { name } </ h1 >
328+ < div >
329+ Params{ ' ' }
330+ < span data-testid = "params" > { JSON . stringify ( routeParams ) } </ span >
331+ Matches{ ' ' }
332+ < span data-testid = "matches" >
333+ { JSON . stringify ( matchRouteMatch ) }
334+ </ span >
335+ </ div >
336+ </ div >
337+ )
338+ }
339+
340+ const router = createRouter ( {
341+ routeTree : rootRoute . addChildren ( [ Route ] ) ,
342+ history : createMemoryHistory ( { initialEntries : [ '/' ] } ) ,
343+ } )
344+
345+ await act ( ( ) => render ( < RouterProvider router = { router } /> ) )
346+
347+ act ( ( ) => router . history . push ( nav ) )
348+
349+ const paramsToCheck = await screen . findByTestId ( 'params' )
350+ const matchesToCheck = await screen . findByTestId ( 'matches' )
351+
352+ expect ( JSON . parse ( paramsToCheck . textContent ) ) . toEqual ( params )
353+ expect ( JSON . parse ( matchesToCheck . textContent ) ) . toEqual ( matchParams )
354+ } ,
355+ )
356+ } )
0 commit comments