From 7730e3389d49106bcfac0747bb015cb81982620a Mon Sep 17 00:00:00 2001 From: Nico Lynzaad Date: Thu, 11 Sep 2025 22:45:44 +0200 Subject: [PATCH 1/4] clean wildcards from _strictParams --- packages/router-core/src/router.ts | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/packages/router-core/src/router.ts b/packages/router-core/src/router.ts index 485d0edb40a..5137372465c 100644 --- a/packages/router-core/src/router.ts +++ b/packages/router-core/src/router.ts @@ -1183,27 +1183,26 @@ export class RouterCore< const loaderDepsHash = loaderDeps ? JSON.stringify(loaderDeps) : '' - const { interpolatedPath } = interpolatePath({ + const { interpolatedPath, usedParams } = interpolatePath({ path: route.fullPath, params: routeParams, decodeCharMap: this.pathParamsDecodeCharMap, }) - const interpolatePathResult = interpolatePath({ - path: route.id, - params: routeParams, - leaveWildcards: true, - decodeCharMap: this.pathParamsDecodeCharMap, - parseCache: this.parsePathnameCache, - }) - // Waste not, want not. If we already have a match for this route, // reuse it. This is important for layout routes, which might stick // around between navigation actions that only change leaf routes. // Existing matches are matches that are already loaded along with // pending matches that are still loading - const matchId = interpolatePathResult.interpolatedPath + loaderDepsHash + const matchId = + interpolatePath({ + path: route.id, + params: routeParams, + leaveWildcards: true, + decodeCharMap: this.pathParamsDecodeCharMap, + parseCache: this.parsePathnameCache, + }).interpolatedPath + loaderDepsHash const existingMatch = this.getMatch(matchId) @@ -1211,8 +1210,7 @@ export class RouterCore< (d) => d.routeId === route.id, ) - const strictParams = - existingMatch?._strictParams ?? interpolatePathResult.usedParams + const strictParams = existingMatch?._strictParams ?? usedParams let paramsError: PathParamError | undefined = undefined From 3cf7a9ee32775e629b9620ab68501ef5a1de770c Mon Sep 17 00:00:00 2001 From: Nico Lynzaad Date: Thu, 11 Sep 2025 22:47:37 +0200 Subject: [PATCH 2/4] add e2e tests for react and solid --- .../basic-file-based/src/routeTree.gen.ts | 88 ++++++++++++++ .../src/routes/params-ps/index.tsx | 12 +- .../params-ps/non-nested/$foo_/$bar.tsx | 19 +++ .../params-ps/non-nested/$foo_/route.tsx | 9 ++ .../src/routes/params-ps/non-nested/route.tsx | 26 +++++ .../basic-file-based/tests/params.spec.ts | 31 +++++ .../basic-file-based/src/routeTree.gen.ts | 109 ++++++++++++++++++ .../src/routes/params-ps/index.tsx | 33 ++++++ .../params-ps/non-nested/$foo_/$bar.tsx | 19 +++ .../params-ps/non-nested/$foo_/route.tsx | 9 ++ .../src/routes/params-ps/non-nested/route.tsx | 26 +++++ .../basic-file-based/tests/params.spec.ts | 31 +++++ 12 files changed, 410 insertions(+), 2 deletions(-) create mode 100644 e2e/react-router/basic-file-based/src/routes/params-ps/non-nested/$foo_/$bar.tsx create mode 100644 e2e/react-router/basic-file-based/src/routes/params-ps/non-nested/$foo_/route.tsx create mode 100644 e2e/react-router/basic-file-based/src/routes/params-ps/non-nested/route.tsx create mode 100644 e2e/solid-router/basic-file-based/src/routes/params-ps/index.tsx create mode 100644 e2e/solid-router/basic-file-based/src/routes/params-ps/non-nested/$foo_/$bar.tsx create mode 100644 e2e/solid-router/basic-file-based/src/routes/params-ps/non-nested/$foo_/route.tsx create mode 100644 e2e/solid-router/basic-file-based/src/routes/params-ps/non-nested/route.tsx diff --git a/e2e/react-router/basic-file-based/src/routeTree.gen.ts b/e2e/react-router/basic-file-based/src/routeTree.gen.ts index 6c4c9159418..2ba33a64143 100644 --- a/e2e/react-router/basic-file-based/src/routeTree.gen.ts +++ b/e2e/react-router/basic-file-based/src/routeTree.gen.ts @@ -38,6 +38,7 @@ import { Route as groupLayoutRouteImport } from './routes/(group)/_layout' import { Route as anotherGroupOnlyrouteinsideRouteImport } from './routes/(another-group)/onlyrouteinside' import { Route as RelativeUseNavigateRouteRouteImport } from './routes/relative/useNavigate/route' import { Route as RelativeLinkRouteRouteImport } from './routes/relative/link/route' +import { Route as ParamsPsNonNestedRouteRouteImport } from './routes/params-ps/non-nested/route' import { Route as RedirectTargetIndexRouteImport } from './routes/redirect/$target/index' import { Route as ParamsPsWildcardIndexRouteImport } from './routes/params-ps/wildcard/index' import { Route as ParamsPsNamedIndexRouteImport } from './routes/params-ps/named/index' @@ -61,6 +62,7 @@ import { Route as LayoutLayout2LayoutBRouteImport } from './routes/_layout/_layo import { Route as LayoutLayout2LayoutARouteImport } from './routes/_layout/_layout-2/layout-a' import { Route as groupSubfolderInsideRouteImport } from './routes/(group)/subfolder/inside' import { Route as groupLayoutInsidelayoutRouteImport } from './routes/(group)/_layout.insidelayout' +import { Route as ParamsPsNonNestedFooRouteRouteImport } from './routes/params-ps/non-nested/$foo_/route' import { Route as ParamsPsNamedFooRouteRouteImport } from './routes/params-ps/named/$foo/route' import { Route as RelativeUseNavigateWithSearchIndexRouteImport } from './routes/relative/useNavigate/with-search/index' import { Route as RelativeUseNavigatePathIndexRouteImport } from './routes/relative/useNavigate/path/index' @@ -68,6 +70,7 @@ import { Route as RelativeUseNavigateNestedIndexRouteImport } from './routes/rel import { Route as RelativeLinkWithSearchIndexRouteImport } from './routes/relative/link/with-search/index' import { Route as RelativeLinkPathIndexRouteImport } from './routes/relative/link/path/index' import { Route as RelativeLinkNestedIndexRouteImport } from './routes/relative/link/nested/index' +import { Route as ParamsPsNonNestedFooBarRouteImport } from './routes/params-ps/non-nested/$foo_/$bar' import { Route as ParamsPsNamedFooBarRouteRouteImport } from './routes/params-ps/named/$foo/$bar.route' import { Route as RelativeUseNavigatePathPathIndexRouteImport } from './routes/relative/useNavigate/path/$path/index' import { Route as RelativeUseNavigateNestedDeepIndexRouteImport } from './routes/relative/useNavigate/nested/deep/index' @@ -219,6 +222,11 @@ const RelativeLinkRouteRoute = RelativeLinkRouteRouteImport.update({ path: '/relative/link', getParentRoute: () => rootRouteImport, } as any) +const ParamsPsNonNestedRouteRoute = ParamsPsNonNestedRouteRouteImport.update({ + id: '/params-ps/non-nested', + path: '/params-ps/non-nested', + getParentRoute: () => rootRouteImport, +} as any) const RedirectTargetIndexRoute = RedirectTargetIndexRouteImport.update({ id: '/', path: '/', @@ -343,6 +351,12 @@ const groupLayoutInsidelayoutRoute = groupLayoutInsidelayoutRouteImport.update({ path: '/insidelayout', getParentRoute: () => groupLayoutRoute, } as any) +const ParamsPsNonNestedFooRouteRoute = + ParamsPsNonNestedFooRouteRouteImport.update({ + id: '/$foo_', + path: '/$foo', + getParentRoute: () => ParamsPsNonNestedRouteRoute, + } as any) const ParamsPsNamedFooRouteRoute = ParamsPsNamedFooRouteRouteImport.update({ id: '/params-ps/named/$foo', path: '/params-ps/named/$foo', @@ -382,6 +396,11 @@ const RelativeLinkNestedIndexRoute = RelativeLinkNestedIndexRouteImport.update({ path: '/nested/', getParentRoute: () => RelativeLinkRouteRoute, } as any) +const ParamsPsNonNestedFooBarRoute = ParamsPsNonNestedFooBarRouteImport.update({ + id: '/$bar', + path: '/$bar', + getParentRoute: () => ParamsPsNonNestedFooRouteRoute, +} as any) const ParamsPsNamedFooBarRouteRoute = ParamsPsNamedFooBarRouteRouteImport.update({ id: '/$bar', @@ -429,6 +448,7 @@ export interface FileRoutesByFullPath { '/posts': typeof PostsRouteWithChildren '/remountDeps': typeof RemountDepsRoute '/대한민국': typeof Char45824Char54620Char48124Char44397Route + '/params-ps/non-nested': typeof ParamsPsNonNestedRouteRouteWithChildren '/relative/link': typeof RelativeLinkRouteRouteWithChildren '/relative/useNavigate': typeof RelativeUseNavigateRouteRouteWithChildren '/onlyrouteinside': typeof anotherGroupOnlyrouteinsideRoute @@ -444,6 +464,7 @@ export interface FileRoutesByFullPath { '/relative': typeof RelativeIndexRoute '/search-params/': typeof SearchParamsIndexRoute '/params-ps/named/$foo': typeof ParamsPsNamedFooRouteRouteWithChildren + '/params-ps/non-nested/$foo': typeof ParamsPsNonNestedFooRouteRouteWithChildren '/insidelayout': typeof groupLayoutInsidelayoutRoute '/subfolder/inside': typeof groupSubfolderInsideRoute '/layout-a': typeof LayoutLayout2LayoutARoute @@ -468,6 +489,7 @@ export interface FileRoutesByFullPath { '/params-ps/wildcard': typeof ParamsPsWildcardIndexRoute '/redirect/$target/': typeof RedirectTargetIndexRoute '/params-ps/named/$foo/$bar': typeof ParamsPsNamedFooBarRouteRouteWithChildren + '/params-ps/non-nested/$foo/$bar': typeof ParamsPsNonNestedFooBarRoute '/relative/link/nested': typeof RelativeLinkNestedIndexRoute '/relative/link/path': typeof RelativeLinkPathIndexRoute '/relative/link/with-search': typeof RelativeLinkWithSearchIndexRoute @@ -489,6 +511,7 @@ export interface FileRoutesByTo { '/notRemountDeps': typeof NotRemountDepsRoute '/remountDeps': typeof RemountDepsRoute '/대한민국': typeof Char45824Char54620Char48124Char44397Route + '/params-ps/non-nested': typeof ParamsPsNonNestedRouteRouteWithChildren '/relative/link': typeof RelativeLinkRouteRouteWithChildren '/relative/useNavigate': typeof RelativeUseNavigateRouteRouteWithChildren '/onlyrouteinside': typeof anotherGroupOnlyrouteinsideRoute @@ -503,6 +526,7 @@ export interface FileRoutesByTo { '/relative': typeof RelativeIndexRoute '/search-params': typeof SearchParamsIndexRoute '/params-ps/named/$foo': typeof ParamsPsNamedFooRouteRouteWithChildren + '/params-ps/non-nested/$foo': typeof ParamsPsNonNestedFooRouteRouteWithChildren '/insidelayout': typeof groupLayoutInsidelayoutRoute '/subfolder/inside': typeof groupSubfolderInsideRoute '/layout-a': typeof LayoutLayout2LayoutARoute @@ -527,6 +551,7 @@ export interface FileRoutesByTo { '/params-ps/wildcard': typeof ParamsPsWildcardIndexRoute '/redirect/$target': typeof RedirectTargetIndexRoute '/params-ps/named/$foo/$bar': typeof ParamsPsNamedFooBarRouteRouteWithChildren + '/params-ps/non-nested/$foo/$bar': typeof ParamsPsNonNestedFooBarRoute '/relative/link/nested': typeof RelativeLinkNestedIndexRoute '/relative/link/path': typeof RelativeLinkPathIndexRoute '/relative/link/with-search': typeof RelativeLinkWithSearchIndexRoute @@ -552,6 +577,7 @@ export interface FileRoutesById { '/posts': typeof PostsRouteWithChildren '/remountDeps': typeof RemountDepsRoute '/대한민국': typeof Char45824Char54620Char48124Char44397Route + '/params-ps/non-nested': typeof ParamsPsNonNestedRouteRouteWithChildren '/relative/link': typeof RelativeLinkRouteRouteWithChildren '/relative/useNavigate': typeof RelativeUseNavigateRouteRouteWithChildren '/(another-group)/onlyrouteinside': typeof anotherGroupOnlyrouteinsideRoute @@ -570,6 +596,7 @@ export interface FileRoutesById { '/relative/': typeof RelativeIndexRoute '/search-params/': typeof SearchParamsIndexRoute '/params-ps/named/$foo': typeof ParamsPsNamedFooRouteRouteWithChildren + '/params-ps/non-nested/$foo_': typeof ParamsPsNonNestedFooRouteRouteWithChildren '/(group)/_layout/insidelayout': typeof groupLayoutInsidelayoutRoute '/(group)/subfolder/inside': typeof groupSubfolderInsideRoute '/_layout/_layout-2/layout-a': typeof LayoutLayout2LayoutARoute @@ -594,6 +621,7 @@ export interface FileRoutesById { '/params-ps/wildcard/': typeof ParamsPsWildcardIndexRoute '/redirect/$target/': typeof RedirectTargetIndexRoute '/params-ps/named/$foo/$bar': typeof ParamsPsNamedFooBarRouteRouteWithChildren + '/params-ps/non-nested/$foo_/$bar': typeof ParamsPsNonNestedFooBarRoute '/relative/link/nested/': typeof RelativeLinkNestedIndexRoute '/relative/link/path/': typeof RelativeLinkPathIndexRoute '/relative/link/with-search/': typeof RelativeLinkWithSearchIndexRoute @@ -619,6 +647,7 @@ export interface FileRouteTypes { | '/posts' | '/remountDeps' | '/대한민국' + | '/params-ps/non-nested' | '/relative/link' | '/relative/useNavigate' | '/onlyrouteinside' @@ -634,6 +663,7 @@ export interface FileRouteTypes { | '/relative' | '/search-params/' | '/params-ps/named/$foo' + | '/params-ps/non-nested/$foo' | '/insidelayout' | '/subfolder/inside' | '/layout-a' @@ -658,6 +688,7 @@ export interface FileRouteTypes { | '/params-ps/wildcard' | '/redirect/$target/' | '/params-ps/named/$foo/$bar' + | '/params-ps/non-nested/$foo/$bar' | '/relative/link/nested' | '/relative/link/path' | '/relative/link/with-search' @@ -679,6 +710,7 @@ export interface FileRouteTypes { | '/notRemountDeps' | '/remountDeps' | '/대한민국' + | '/params-ps/non-nested' | '/relative/link' | '/relative/useNavigate' | '/onlyrouteinside' @@ -693,6 +725,7 @@ export interface FileRouteTypes { | '/relative' | '/search-params' | '/params-ps/named/$foo' + | '/params-ps/non-nested/$foo' | '/insidelayout' | '/subfolder/inside' | '/layout-a' @@ -717,6 +750,7 @@ export interface FileRouteTypes { | '/params-ps/wildcard' | '/redirect/$target' | '/params-ps/named/$foo/$bar' + | '/params-ps/non-nested/$foo/$bar' | '/relative/link/nested' | '/relative/link/path' | '/relative/link/with-search' @@ -741,6 +775,7 @@ export interface FileRouteTypes { | '/posts' | '/remountDeps' | '/대한민국' + | '/params-ps/non-nested' | '/relative/link' | '/relative/useNavigate' | '/(another-group)/onlyrouteinside' @@ -759,6 +794,7 @@ export interface FileRouteTypes { | '/relative/' | '/search-params/' | '/params-ps/named/$foo' + | '/params-ps/non-nested/$foo_' | '/(group)/_layout/insidelayout' | '/(group)/subfolder/inside' | '/_layout/_layout-2/layout-a' @@ -783,6 +819,7 @@ export interface FileRouteTypes { | '/params-ps/wildcard/' | '/redirect/$target/' | '/params-ps/named/$foo/$bar' + | '/params-ps/non-nested/$foo_/$bar' | '/relative/link/nested/' | '/relative/link/path/' | '/relative/link/with-search/' @@ -808,6 +845,7 @@ export interface RootRouteChildren { PostsRoute: typeof PostsRouteWithChildren RemountDepsRoute: typeof RemountDepsRoute Char45824Char54620Char48124Char44397Route: typeof Char45824Char54620Char48124Char44397Route + ParamsPsNonNestedRouteRoute: typeof ParamsPsNonNestedRouteRouteWithChildren RelativeLinkRouteRoute: typeof RelativeLinkRouteRouteWithChildren RelativeUseNavigateRouteRoute: typeof RelativeUseNavigateRouteRouteWithChildren anotherGroupOnlyrouteinsideRoute: typeof anotherGroupOnlyrouteinsideRoute @@ -1030,6 +1068,13 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof RelativeLinkRouteRouteImport parentRoute: typeof rootRouteImport } + '/params-ps/non-nested': { + id: '/params-ps/non-nested' + path: '/params-ps/non-nested' + fullPath: '/params-ps/non-nested' + preLoaderRoute: typeof ParamsPsNonNestedRouteRouteImport + parentRoute: typeof rootRouteImport + } '/redirect/$target/': { id: '/redirect/$target/' path: '/' @@ -1191,6 +1236,13 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof groupLayoutInsidelayoutRouteImport parentRoute: typeof groupLayoutRoute } + '/params-ps/non-nested/$foo_': { + id: '/params-ps/non-nested/$foo_' + path: '/$foo' + fullPath: '/params-ps/non-nested/$foo' + preLoaderRoute: typeof ParamsPsNonNestedFooRouteRouteImport + parentRoute: typeof ParamsPsNonNestedRouteRoute + } '/params-ps/named/$foo': { id: '/params-ps/named/$foo' path: '/params-ps/named/$foo' @@ -1240,6 +1292,13 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof RelativeLinkNestedIndexRouteImport parentRoute: typeof RelativeLinkRouteRoute } + '/params-ps/non-nested/$foo_/$bar': { + id: '/params-ps/non-nested/$foo_/$bar' + path: '/$bar' + fullPath: '/params-ps/non-nested/$foo/$bar' + preLoaderRoute: typeof ParamsPsNonNestedFooBarRouteImport + parentRoute: typeof ParamsPsNonNestedFooRouteRoute + } '/params-ps/named/$foo/$bar': { id: '/params-ps/named/$foo/$bar' path: '/$bar' @@ -1335,6 +1394,34 @@ const PostsRouteChildren: PostsRouteChildren = { const PostsRouteWithChildren = PostsRoute._addFileChildren(PostsRouteChildren) +interface ParamsPsNonNestedFooRouteRouteChildren { + ParamsPsNonNestedFooBarRoute: typeof ParamsPsNonNestedFooBarRoute +} + +const ParamsPsNonNestedFooRouteRouteChildren: ParamsPsNonNestedFooRouteRouteChildren = + { + ParamsPsNonNestedFooBarRoute: ParamsPsNonNestedFooBarRoute, + } + +const ParamsPsNonNestedFooRouteRouteWithChildren = + ParamsPsNonNestedFooRouteRoute._addFileChildren( + ParamsPsNonNestedFooRouteRouteChildren, + ) + +interface ParamsPsNonNestedRouteRouteChildren { + ParamsPsNonNestedFooRouteRoute: typeof ParamsPsNonNestedFooRouteRouteWithChildren +} + +const ParamsPsNonNestedRouteRouteChildren: ParamsPsNonNestedRouteRouteChildren = + { + ParamsPsNonNestedFooRouteRoute: ParamsPsNonNestedFooRouteRouteWithChildren, + } + +const ParamsPsNonNestedRouteRouteWithChildren = + ParamsPsNonNestedRouteRoute._addFileChildren( + ParamsPsNonNestedRouteRouteChildren, + ) + interface RelativeLinkRouteRouteChildren { RelativeLinkRelativeLinkARoute: typeof RelativeLinkRelativeLinkARoute RelativeLinkRelativeLinkBRoute: typeof RelativeLinkRelativeLinkBRoute @@ -1473,6 +1560,7 @@ const rootRouteChildren: RootRouteChildren = { RemountDepsRoute: RemountDepsRoute, Char45824Char54620Char48124Char44397Route: Char45824Char54620Char48124Char44397Route, + ParamsPsNonNestedRouteRoute: ParamsPsNonNestedRouteRouteWithChildren, RelativeLinkRouteRoute: RelativeLinkRouteRouteWithChildren, RelativeUseNavigateRouteRoute: RelativeUseNavigateRouteRouteWithChildren, anotherGroupOnlyrouteinsideRoute: anotherGroupOnlyrouteinsideRoute, diff --git a/e2e/react-router/basic-file-based/src/routes/params-ps/index.tsx b/e2e/react-router/basic-file-based/src/routes/params-ps/index.tsx index 67893d7d235..ddaae248767 100644 --- a/e2e/react-router/basic-file-based/src/routes/params-ps/index.tsx +++ b/e2e/react-router/basic-file-based/src/routes/params-ps/index.tsx @@ -1,5 +1,4 @@ -import { createFileRoute } from '@tanstack/react-router' -import { Link } from '@tanstack/react-router' +import { Link, createFileRoute } from '@tanstack/react-router' export const Route = createFileRoute('/params-ps/')({ component: RouteComponent, @@ -69,6 +68,15 @@ function RouteComponent() { +
+

Non-nested path params

+ ) } diff --git a/e2e/react-router/basic-file-based/src/routes/params-ps/non-nested/$foo_/$bar.tsx b/e2e/react-router/basic-file-based/src/routes/params-ps/non-nested/$foo_/$bar.tsx new file mode 100644 index 00000000000..4f1406030d7 --- /dev/null +++ b/e2e/react-router/basic-file-based/src/routes/params-ps/non-nested/$foo_/$bar.tsx @@ -0,0 +1,19 @@ +import { createFileRoute, useParams } from '@tanstack/react-router' + +export const Route = createFileRoute('/params-ps/non-nested/$foo_/$bar')({ + component: RouteComponent, +}) + +function RouteComponent() { + const fooParams = useParams({ from: '/params-ps/non-nested/$foo_' }) + const routeParams = Route.useParams() + + return ( +
+
{JSON.stringify(fooParams)}
+
+ {JSON.stringify(routeParams)} +
+
+ ) +} diff --git a/e2e/react-router/basic-file-based/src/routes/params-ps/non-nested/$foo_/route.tsx b/e2e/react-router/basic-file-based/src/routes/params-ps/non-nested/$foo_/route.tsx new file mode 100644 index 00000000000..169655a3cb5 --- /dev/null +++ b/e2e/react-router/basic-file-based/src/routes/params-ps/non-nested/$foo_/route.tsx @@ -0,0 +1,9 @@ +import { Outlet, createFileRoute } from '@tanstack/react-router' + +export const Route = createFileRoute('/params-ps/non-nested/$foo_')({ + component: RouteComponent, +}) + +function RouteComponent() { + return +} diff --git a/e2e/react-router/basic-file-based/src/routes/params-ps/non-nested/route.tsx b/e2e/react-router/basic-file-based/src/routes/params-ps/non-nested/route.tsx new file mode 100644 index 00000000000..4b5d670d3af --- /dev/null +++ b/e2e/react-router/basic-file-based/src/routes/params-ps/non-nested/route.tsx @@ -0,0 +1,26 @@ +import { Link, Outlet, createFileRoute } from '@tanstack/react-router' + +export const Route = createFileRoute('/params-ps/non-nested')({ + component: RouteComponent, +}) + +function RouteComponent() { + return ( +
+

Non-nested path params

+
    +
  • + + /params-ps/non-nested/$foo/$bar + +
  • + +
+
+ ) +} diff --git a/e2e/react-router/basic-file-based/tests/params.spec.ts b/e2e/react-router/basic-file-based/tests/params.spec.ts index 59dc844fd81..d4d6d2e602b 100644 --- a/e2e/react-router/basic-file-based/tests/params.spec.ts +++ b/e2e/react-router/basic-file-based/tests/params.spec.ts @@ -55,6 +55,37 @@ test.describe('ensure single params have been parsed correctly whilst being stab } }) +test.describe('params operations + non-nested routes', () => { + test.beforeEach(async ({ page }) => { + await page.goto('/params-ps/non-nested') + }) + + test('useParams must resolve non-nested path params', async ({ page }) => { + await page.waitForURL('/params-ps/non-nested') + + const fooBarLink = page.getByTestId('l-to-non-nested-foo-bar') + + await expect(fooBarLink).toHaveAttribute( + 'href', + '/params-ps/non-nested/foo/bar', + ) + await fooBarLink.click() + await page.waitForLoadState('networkidle') + const pagePathname = new URL(page.url()).pathname + expect(pagePathname).toBe('/params-ps/non-nested/foo/bar') + + const fooParamsValue = page.getByTestId('foo-params-value') + const fooParamsText = await fooParamsValue.innerText() + const fooParamsObj = JSON.parse(fooParamsText) + expect(fooParamsObj).toEqual({ foo: 'foo' }) + + const paramsValue = page.getByTestId('foo-bar-params-value') + const paramsText = await paramsValue.innerText() + const paramsObj = JSON.parse(paramsText) + expect(paramsObj).toEqual({ foo: 'foo', bar: 'bar' }) + }) +}) + test.describe('params operations + prefix/suffix', () => { test.beforeEach(async ({ page }) => { await page.goto('/params-ps') diff --git a/e2e/solid-router/basic-file-based/src/routeTree.gen.ts b/e2e/solid-router/basic-file-based/src/routeTree.gen.ts index 1fa808525cb..f4b02f10a84 100644 --- a/e2e/solid-router/basic-file-based/src/routeTree.gen.ts +++ b/e2e/solid-router/basic-file-based/src/routeTree.gen.ts @@ -25,6 +25,7 @@ import { Route as SearchParamsIndexRouteImport } from './routes/search-params/in import { Route as RelativeIndexRouteImport } from './routes/relative/index' import { Route as RedirectIndexRouteImport } from './routes/redirect/index' import { Route as PostsIndexRouteImport } from './routes/posts.index' +import { Route as ParamsPsIndexRouteImport } from './routes/params-ps/index' import { Route as SearchParamsDefaultRouteImport } from './routes/search-params/default' import { Route as RedirectTargetRouteImport } from './routes/redirect/$target' import { Route as PostsPostIdRouteImport } from './routes/posts.$postId' @@ -35,6 +36,7 @@ import { Route as groupLayoutRouteImport } from './routes/(group)/_layout' import { Route as anotherGroupOnlyrouteinsideRouteImport } from './routes/(another-group)/onlyrouteinside' import { Route as RelativeUseNavigateRouteRouteImport } from './routes/relative/useNavigate/route' import { Route as RelativeLinkRouteRouteImport } from './routes/relative/link/route' +import { Route as ParamsPsNonNestedRouteRouteImport } from './routes/params-ps/non-nested/route' import { Route as RedirectTargetIndexRouteImport } from './routes/redirect/$target/index' import { Route as RelativeUseNavigateRelativeUseNavigateBRouteImport } from './routes/relative/useNavigate/relative-useNavigate-b' import { Route as RelativeUseNavigateRelativeUseNavigateARouteImport } from './routes/relative/useNavigate/relative-useNavigate-a' @@ -51,6 +53,7 @@ import { Route as LayoutLayout2LayoutBRouteImport } from './routes/_layout/_layo import { Route as LayoutLayout2LayoutARouteImport } from './routes/_layout/_layout-2/layout-a' import { Route as groupSubfolderInsideRouteImport } from './routes/(group)/subfolder/inside' import { Route as groupLayoutInsidelayoutRouteImport } from './routes/(group)/_layout.insidelayout' +import { Route as ParamsPsNonNestedFooRouteRouteImport } from './routes/params-ps/non-nested/$foo_/route' import { Route as ParamsPsNamedFooRouteRouteImport } from './routes/params-ps/named/$foo/route' import { Route as RelativeUseNavigateWithSearchIndexRouteImport } from './routes/relative/useNavigate/with-search/index' import { Route as RelativeUseNavigatePathIndexRouteImport } from './routes/relative/useNavigate/path/index' @@ -58,6 +61,7 @@ import { Route as RelativeUseNavigateNestedIndexRouteImport } from './routes/rel import { Route as RelativeLinkWithSearchIndexRouteImport } from './routes/relative/link/with-search/index' import { Route as RelativeLinkPathIndexRouteImport } from './routes/relative/link/path/index' import { Route as RelativeLinkNestedIndexRouteImport } from './routes/relative/link/nested/index' +import { Route as ParamsPsNonNestedFooBarRouteImport } from './routes/params-ps/non-nested/$foo_/$bar' import { Route as ParamsPsNamedFooBarRouteRouteImport } from './routes/params-ps/named/$foo/$bar.route' import { Route as RelativeUseNavigatePathPathIndexRouteImport } from './routes/relative/useNavigate/path/$path/index' import { Route as RelativeUseNavigateNestedDeepIndexRouteImport } from './routes/relative/useNavigate/nested/deep/index' @@ -140,6 +144,11 @@ const PostsIndexRoute = PostsIndexRouteImport.update({ path: '/', getParentRoute: () => PostsRoute, } as any) +const ParamsPsIndexRoute = ParamsPsIndexRouteImport.update({ + id: '/params-ps/', + path: '/params-ps/', + getParentRoute: () => rootRouteImport, +} as any) const SearchParamsDefaultRoute = SearchParamsDefaultRouteImport.update({ id: '/default', path: '/default', @@ -192,6 +201,11 @@ const RelativeLinkRouteRoute = RelativeLinkRouteRouteImport.update({ path: '/relative/link', getParentRoute: () => rootRouteImport, } as any) +const ParamsPsNonNestedRouteRoute = ParamsPsNonNestedRouteRouteImport.update({ + id: '/params-ps/non-nested', + path: '/params-ps/non-nested', + getParentRoute: () => rootRouteImport, +} as any) const RedirectTargetIndexRoute = RedirectTargetIndexRouteImport.update({ id: '/', path: '/', @@ -277,6 +291,12 @@ const groupLayoutInsidelayoutRoute = groupLayoutInsidelayoutRouteImport.update({ path: '/insidelayout', getParentRoute: () => groupLayoutRoute, } as any) +const ParamsPsNonNestedFooRouteRoute = + ParamsPsNonNestedFooRouteRouteImport.update({ + id: '/$foo_', + path: '/$foo', + getParentRoute: () => ParamsPsNonNestedRouteRoute, + } as any) const ParamsPsNamedFooRouteRoute = ParamsPsNamedFooRouteRouteImport.update({ id: '/params-ps/named/$foo', path: '/params-ps/named/$foo', @@ -316,6 +336,11 @@ const RelativeLinkNestedIndexRoute = RelativeLinkNestedIndexRouteImport.update({ path: '/nested/', getParentRoute: () => RelativeLinkRouteRoute, } as any) +const ParamsPsNonNestedFooBarRoute = ParamsPsNonNestedFooBarRouteImport.update({ + id: '/$bar', + path: '/$bar', + getParentRoute: () => ParamsPsNonNestedFooRouteRoute, +} as any) const ParamsPsNamedFooBarRouteRoute = ParamsPsNamedFooBarRouteRouteImport.update({ id: '/$bar', @@ -362,6 +387,7 @@ export interface FileRoutesByFullPath { '/notRemountDeps': typeof NotRemountDepsRoute '/posts': typeof PostsRouteWithChildren '/remountDeps': typeof RemountDepsRoute + '/params-ps/non-nested': typeof ParamsPsNonNestedRouteRouteWithChildren '/relative/link': typeof RelativeLinkRouteRouteWithChildren '/relative/useNavigate': typeof RelativeUseNavigateRouteRouteWithChildren '/onlyrouteinside': typeof anotherGroupOnlyrouteinsideRoute @@ -370,11 +396,13 @@ export interface FileRoutesByFullPath { '/posts/$postId': typeof PostsPostIdRoute '/redirect/$target': typeof RedirectTargetRouteWithChildren '/search-params/default': typeof SearchParamsDefaultRoute + '/params-ps': typeof ParamsPsIndexRoute '/posts/': typeof PostsIndexRoute '/redirect': typeof RedirectIndexRoute '/relative': typeof RelativeIndexRoute '/search-params/': typeof SearchParamsIndexRoute '/params-ps/named/$foo': typeof ParamsPsNamedFooRouteRouteWithChildren + '/params-ps/non-nested/$foo': typeof ParamsPsNonNestedFooRouteRouteWithChildren '/insidelayout': typeof groupLayoutInsidelayoutRoute '/subfolder/inside': typeof groupSubfolderInsideRoute '/layout-a': typeof LayoutLayout2LayoutARoute @@ -392,6 +420,7 @@ export interface FileRoutesByFullPath { '/relative/useNavigate/relative-useNavigate-b': typeof RelativeUseNavigateRelativeUseNavigateBRoute '/redirect/$target/': typeof RedirectTargetIndexRoute '/params-ps/named/$foo/$bar': typeof ParamsPsNamedFooBarRouteRouteWithChildren + '/params-ps/non-nested/$foo/$bar': typeof ParamsPsNonNestedFooBarRoute '/relative/link/nested': typeof RelativeLinkNestedIndexRoute '/relative/link/path': typeof RelativeLinkPathIndexRoute '/relative/link/with-search': typeof RelativeLinkWithSearchIndexRoute @@ -412,6 +441,7 @@ export interface FileRoutesByTo { '/editing-b': typeof EditingBRoute '/notRemountDeps': typeof NotRemountDepsRoute '/remountDeps': typeof RemountDepsRoute + '/params-ps/non-nested': typeof ParamsPsNonNestedRouteRouteWithChildren '/relative/link': typeof RelativeLinkRouteRouteWithChildren '/relative/useNavigate': typeof RelativeUseNavigateRouteRouteWithChildren '/onlyrouteinside': typeof anotherGroupOnlyrouteinsideRoute @@ -419,11 +449,13 @@ export interface FileRoutesByTo { '/lazyinside': typeof groupLazyinsideRoute '/posts/$postId': typeof PostsPostIdRoute '/search-params/default': typeof SearchParamsDefaultRoute + '/params-ps': typeof ParamsPsIndexRoute '/posts': typeof PostsIndexRoute '/redirect': typeof RedirectIndexRoute '/relative': typeof RelativeIndexRoute '/search-params': typeof SearchParamsIndexRoute '/params-ps/named/$foo': typeof ParamsPsNamedFooRouteRouteWithChildren + '/params-ps/non-nested/$foo': typeof ParamsPsNonNestedFooRouteRouteWithChildren '/insidelayout': typeof groupLayoutInsidelayoutRoute '/subfolder/inside': typeof groupSubfolderInsideRoute '/layout-a': typeof LayoutLayout2LayoutARoute @@ -441,6 +473,7 @@ export interface FileRoutesByTo { '/relative/useNavigate/relative-useNavigate-b': typeof RelativeUseNavigateRelativeUseNavigateBRoute '/redirect/$target': typeof RedirectTargetIndexRoute '/params-ps/named/$foo/$bar': typeof ParamsPsNamedFooBarRouteRouteWithChildren + '/params-ps/non-nested/$foo/$bar': typeof ParamsPsNonNestedFooBarRoute '/relative/link/nested': typeof RelativeLinkNestedIndexRoute '/relative/link/path': typeof RelativeLinkPathIndexRoute '/relative/link/with-search': typeof RelativeLinkWithSearchIndexRoute @@ -465,6 +498,7 @@ export interface FileRoutesById { '/notRemountDeps': typeof NotRemountDepsRoute '/posts': typeof PostsRouteWithChildren '/remountDeps': typeof RemountDepsRoute + '/params-ps/non-nested': typeof ParamsPsNonNestedRouteRouteWithChildren '/relative/link': typeof RelativeLinkRouteRouteWithChildren '/relative/useNavigate': typeof RelativeUseNavigateRouteRouteWithChildren '/(another-group)/onlyrouteinside': typeof anotherGroupOnlyrouteinsideRoute @@ -476,11 +510,13 @@ export interface FileRoutesById { '/posts/$postId': typeof PostsPostIdRoute '/redirect/$target': typeof RedirectTargetRouteWithChildren '/search-params/default': typeof SearchParamsDefaultRoute + '/params-ps/': typeof ParamsPsIndexRoute '/posts/': typeof PostsIndexRoute '/redirect/': typeof RedirectIndexRoute '/relative/': typeof RelativeIndexRoute '/search-params/': typeof SearchParamsIndexRoute '/params-ps/named/$foo': typeof ParamsPsNamedFooRouteRouteWithChildren + '/params-ps/non-nested/$foo_': typeof ParamsPsNonNestedFooRouteRouteWithChildren '/(group)/_layout/insidelayout': typeof groupLayoutInsidelayoutRoute '/(group)/subfolder/inside': typeof groupSubfolderInsideRoute '/_layout/_layout-2/layout-a': typeof LayoutLayout2LayoutARoute @@ -498,6 +534,7 @@ export interface FileRoutesById { '/relative/useNavigate/relative-useNavigate-b': typeof RelativeUseNavigateRelativeUseNavigateBRoute '/redirect/$target/': typeof RedirectTargetIndexRoute '/params-ps/named/$foo/$bar': typeof ParamsPsNamedFooBarRouteRouteWithChildren + '/params-ps/non-nested/$foo_/$bar': typeof ParamsPsNonNestedFooBarRoute '/relative/link/nested/': typeof RelativeLinkNestedIndexRoute '/relative/link/path/': typeof RelativeLinkPathIndexRoute '/relative/link/with-search/': typeof RelativeLinkWithSearchIndexRoute @@ -522,6 +559,7 @@ export interface FileRouteTypes { | '/notRemountDeps' | '/posts' | '/remountDeps' + | '/params-ps/non-nested' | '/relative/link' | '/relative/useNavigate' | '/onlyrouteinside' @@ -530,11 +568,13 @@ export interface FileRouteTypes { | '/posts/$postId' | '/redirect/$target' | '/search-params/default' + | '/params-ps' | '/posts/' | '/redirect' | '/relative' | '/search-params/' | '/params-ps/named/$foo' + | '/params-ps/non-nested/$foo' | '/insidelayout' | '/subfolder/inside' | '/layout-a' @@ -552,6 +592,7 @@ export interface FileRouteTypes { | '/relative/useNavigate/relative-useNavigate-b' | '/redirect/$target/' | '/params-ps/named/$foo/$bar' + | '/params-ps/non-nested/$foo/$bar' | '/relative/link/nested' | '/relative/link/path' | '/relative/link/with-search' @@ -572,6 +613,7 @@ export interface FileRouteTypes { | '/editing-b' | '/notRemountDeps' | '/remountDeps' + | '/params-ps/non-nested' | '/relative/link' | '/relative/useNavigate' | '/onlyrouteinside' @@ -579,11 +621,13 @@ export interface FileRouteTypes { | '/lazyinside' | '/posts/$postId' | '/search-params/default' + | '/params-ps' | '/posts' | '/redirect' | '/relative' | '/search-params' | '/params-ps/named/$foo' + | '/params-ps/non-nested/$foo' | '/insidelayout' | '/subfolder/inside' | '/layout-a' @@ -601,6 +645,7 @@ export interface FileRouteTypes { | '/relative/useNavigate/relative-useNavigate-b' | '/redirect/$target' | '/params-ps/named/$foo/$bar' + | '/params-ps/non-nested/$foo/$bar' | '/relative/link/nested' | '/relative/link/path' | '/relative/link/with-search' @@ -624,6 +669,7 @@ export interface FileRouteTypes { | '/notRemountDeps' | '/posts' | '/remountDeps' + | '/params-ps/non-nested' | '/relative/link' | '/relative/useNavigate' | '/(another-group)/onlyrouteinside' @@ -635,11 +681,13 @@ export interface FileRouteTypes { | '/posts/$postId' | '/redirect/$target' | '/search-params/default' + | '/params-ps/' | '/posts/' | '/redirect/' | '/relative/' | '/search-params/' | '/params-ps/named/$foo' + | '/params-ps/non-nested/$foo_' | '/(group)/_layout/insidelayout' | '/(group)/subfolder/inside' | '/_layout/_layout-2/layout-a' @@ -657,6 +705,7 @@ export interface FileRouteTypes { | '/relative/useNavigate/relative-useNavigate-b' | '/redirect/$target/' | '/params-ps/named/$foo/$bar' + | '/params-ps/non-nested/$foo_/$bar' | '/relative/link/nested/' | '/relative/link/path/' | '/relative/link/with-search/' @@ -681,11 +730,13 @@ export interface RootRouteChildren { NotRemountDepsRoute: typeof NotRemountDepsRoute PostsRoute: typeof PostsRouteWithChildren RemountDepsRoute: typeof RemountDepsRoute + ParamsPsNonNestedRouteRoute: typeof ParamsPsNonNestedRouteRouteWithChildren RelativeLinkRouteRoute: typeof RelativeLinkRouteRouteWithChildren RelativeUseNavigateRouteRoute: typeof RelativeUseNavigateRouteRouteWithChildren anotherGroupOnlyrouteinsideRoute: typeof anotherGroupOnlyrouteinsideRoute groupRoute: typeof groupRouteWithChildren RedirectTargetRoute: typeof RedirectTargetRouteWithChildren + ParamsPsIndexRoute: typeof ParamsPsIndexRoute RedirectIndexRoute: typeof RedirectIndexRoute RelativeIndexRoute: typeof RelativeIndexRoute ParamsPsNamedFooRouteRoute: typeof ParamsPsNamedFooRouteRouteWithChildren @@ -803,6 +854,13 @@ declare module '@tanstack/solid-router' { preLoaderRoute: typeof PostsIndexRouteImport parentRoute: typeof PostsRoute } + '/params-ps/': { + id: '/params-ps/' + path: '/params-ps' + fullPath: '/params-ps' + preLoaderRoute: typeof ParamsPsIndexRouteImport + parentRoute: typeof rootRouteImport + } '/search-params/default': { id: '/search-params/default' path: '/default' @@ -873,6 +931,13 @@ declare module '@tanstack/solid-router' { preLoaderRoute: typeof RelativeLinkRouteRouteImport parentRoute: typeof rootRouteImport } + '/params-ps/non-nested': { + id: '/params-ps/non-nested' + path: '/params-ps/non-nested' + fullPath: '/params-ps/non-nested' + preLoaderRoute: typeof ParamsPsNonNestedRouteRouteImport + parentRoute: typeof rootRouteImport + } '/redirect/$target/': { id: '/redirect/$target/' path: '/' @@ -985,6 +1050,13 @@ declare module '@tanstack/solid-router' { preLoaderRoute: typeof groupLayoutInsidelayoutRouteImport parentRoute: typeof groupLayoutRoute } + '/params-ps/non-nested/$foo_': { + id: '/params-ps/non-nested/$foo_' + path: '/$foo' + fullPath: '/params-ps/non-nested/$foo' + preLoaderRoute: typeof ParamsPsNonNestedFooRouteRouteImport + parentRoute: typeof ParamsPsNonNestedRouteRoute + } '/params-ps/named/$foo': { id: '/params-ps/named/$foo' path: '/params-ps/named/$foo' @@ -1034,6 +1106,13 @@ declare module '@tanstack/solid-router' { preLoaderRoute: typeof RelativeLinkNestedIndexRouteImport parentRoute: typeof RelativeLinkRouteRoute } + '/params-ps/non-nested/$foo_/$bar': { + id: '/params-ps/non-nested/$foo_/$bar' + path: '/$bar' + fullPath: '/params-ps/non-nested/$foo/$bar' + preLoaderRoute: typeof ParamsPsNonNestedFooBarRouteImport + parentRoute: typeof ParamsPsNonNestedFooRouteRoute + } '/params-ps/named/$foo/$bar': { id: '/params-ps/named/$foo/$bar' path: '/$bar' @@ -1129,6 +1208,34 @@ const PostsRouteChildren: PostsRouteChildren = { const PostsRouteWithChildren = PostsRoute._addFileChildren(PostsRouteChildren) +interface ParamsPsNonNestedFooRouteRouteChildren { + ParamsPsNonNestedFooBarRoute: typeof ParamsPsNonNestedFooBarRoute +} + +const ParamsPsNonNestedFooRouteRouteChildren: ParamsPsNonNestedFooRouteRouteChildren = + { + ParamsPsNonNestedFooBarRoute: ParamsPsNonNestedFooBarRoute, + } + +const ParamsPsNonNestedFooRouteRouteWithChildren = + ParamsPsNonNestedFooRouteRoute._addFileChildren( + ParamsPsNonNestedFooRouteRouteChildren, + ) + +interface ParamsPsNonNestedRouteRouteChildren { + ParamsPsNonNestedFooRouteRoute: typeof ParamsPsNonNestedFooRouteRouteWithChildren +} + +const ParamsPsNonNestedRouteRouteChildren: ParamsPsNonNestedRouteRouteChildren = + { + ParamsPsNonNestedFooRouteRoute: ParamsPsNonNestedFooRouteRouteWithChildren, + } + +const ParamsPsNonNestedRouteRouteWithChildren = + ParamsPsNonNestedRouteRoute._addFileChildren( + ParamsPsNonNestedRouteRouteChildren, + ) + interface RelativeLinkRouteRouteChildren { RelativeLinkRelativeLinkARoute: typeof RelativeLinkRelativeLinkARoute RelativeLinkRelativeLinkBRoute: typeof RelativeLinkRelativeLinkBRoute @@ -1265,11 +1372,13 @@ const rootRouteChildren: RootRouteChildren = { NotRemountDepsRoute: NotRemountDepsRoute, PostsRoute: PostsRouteWithChildren, RemountDepsRoute: RemountDepsRoute, + ParamsPsNonNestedRouteRoute: ParamsPsNonNestedRouteRouteWithChildren, RelativeLinkRouteRoute: RelativeLinkRouteRouteWithChildren, RelativeUseNavigateRouteRoute: RelativeUseNavigateRouteRouteWithChildren, anotherGroupOnlyrouteinsideRoute: anotherGroupOnlyrouteinsideRoute, groupRoute: groupRouteWithChildren, RedirectTargetRoute: RedirectTargetRouteWithChildren, + ParamsPsIndexRoute: ParamsPsIndexRoute, RedirectIndexRoute: RedirectIndexRoute, RelativeIndexRoute: RelativeIndexRoute, ParamsPsNamedFooRouteRoute: ParamsPsNamedFooRouteRouteWithChildren, diff --git a/e2e/solid-router/basic-file-based/src/routes/params-ps/index.tsx b/e2e/solid-router/basic-file-based/src/routes/params-ps/index.tsx new file mode 100644 index 00000000000..14a840c3a3c --- /dev/null +++ b/e2e/solid-router/basic-file-based/src/routes/params-ps/index.tsx @@ -0,0 +1,33 @@ +import { Link, createFileRoute } from '@tanstack/solid-router' + +export const Route = createFileRoute('/params-ps/')({ + component: RouteComponent, +}) + +function RouteComponent() { + return ( +
+

Named path params

+
    +
  • + + /params-ps/named/$foo + +
  • +
+
+

Non-nested path params

+
    +
  • + + Non-nested + +
  • +
+
+ ) +} diff --git a/e2e/solid-router/basic-file-based/src/routes/params-ps/non-nested/$foo_/$bar.tsx b/e2e/solid-router/basic-file-based/src/routes/params-ps/non-nested/$foo_/$bar.tsx new file mode 100644 index 00000000000..837aa937c2d --- /dev/null +++ b/e2e/solid-router/basic-file-based/src/routes/params-ps/non-nested/$foo_/$bar.tsx @@ -0,0 +1,19 @@ +import { createFileRoute, useParams } from '@tanstack/solid-router' + +export const Route = createFileRoute('/params-ps/non-nested/$foo_/$bar')({ + component: RouteComponent, +}) + +function RouteComponent() { + const fooParams = useParams({ from: '/params-ps/non-nested/$foo_' }) + const routeParams = Route.useParams() + + return ( +
+
{JSON.stringify(fooParams())}
+
+ {JSON.stringify(routeParams())} +
+
+ ) +} diff --git a/e2e/solid-router/basic-file-based/src/routes/params-ps/non-nested/$foo_/route.tsx b/e2e/solid-router/basic-file-based/src/routes/params-ps/non-nested/$foo_/route.tsx new file mode 100644 index 00000000000..96c28d43198 --- /dev/null +++ b/e2e/solid-router/basic-file-based/src/routes/params-ps/non-nested/$foo_/route.tsx @@ -0,0 +1,9 @@ +import { Outlet, createFileRoute } from '@tanstack/solid-router' + +export const Route = createFileRoute('/params-ps/non-nested/$foo_')({ + component: RouteComponent, +}) + +function RouteComponent() { + return +} diff --git a/e2e/solid-router/basic-file-based/src/routes/params-ps/non-nested/route.tsx b/e2e/solid-router/basic-file-based/src/routes/params-ps/non-nested/route.tsx new file mode 100644 index 00000000000..759f6b9a26f --- /dev/null +++ b/e2e/solid-router/basic-file-based/src/routes/params-ps/non-nested/route.tsx @@ -0,0 +1,26 @@ +import { Link, Outlet, createFileRoute } from '@tanstack/solid-router' + +export const Route = createFileRoute('/params-ps/non-nested')({ + component: RouteComponent, +}) + +function RouteComponent() { + return ( +
+

Non-nested path params

+
    +
  • + + /params-ps/non-nested/$foo/$bar + +
  • + +
+
+ ) +} diff --git a/e2e/solid-router/basic-file-based/tests/params.spec.ts b/e2e/solid-router/basic-file-based/tests/params.spec.ts index 42930fc41a1..3a63c934175 100644 --- a/e2e/solid-router/basic-file-based/tests/params.spec.ts +++ b/e2e/solid-router/basic-file-based/tests/params.spec.ts @@ -129,3 +129,34 @@ test('ensure only applicable params are returned and updated with multiple param await expect(fooValue).toHaveText(JSON.stringify({ foo: 'foo' })) await expect(fooRenderCount).toHaveText('1') }) + +test.describe('params operations + non-nested routes', () => { + test.beforeEach(async ({ page }) => { + await page.goto('/params-ps/non-nested') + }) + + test('useParams must resolve non-nested path params', async ({ page }) => { + await page.waitForURL('/params-ps/non-nested') + + const fooBarLink = page.getByTestId('l-to-non-nested-foo-bar') + + await expect(fooBarLink).toHaveAttribute( + 'href', + '/params-ps/non-nested/foo/bar', + ) + await fooBarLink.click() + await page.waitForLoadState('networkidle') + const pagePathname = new URL(page.url()).pathname + expect(pagePathname).toBe('/params-ps/non-nested/foo/bar') + + const fooParamsValue = page.getByTestId('foo-params-value') + const fooParamsText = await fooParamsValue.innerText() + const fooParamsObj = JSON.parse(fooParamsText) + expect(fooParamsObj).toEqual({ foo: 'foo' }) + + const paramsValue = page.getByTestId('foo-bar-params-value') + const paramsText = await paramsValue.innerText() + const paramsObj = JSON.parse(paramsText) + expect(paramsObj).toEqual({ foo: 'foo', bar: 'bar' }) + }) +}) From 522b7e585be481641dd1ede4d5e0227d50c8b1d5 Mon Sep 17 00:00:00 2001 From: Nico Lynzaad Date: Thu, 11 Sep 2025 23:15:52 +0200 Subject: [PATCH 3/4] minor cleanups --- .../src/routes/params-ps/non-nested/$foo_/route.tsx | 10 ++-------- .../src/routes/params-ps/non-nested/$foo_/route.tsx | 10 ++-------- 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/e2e/react-router/basic-file-based/src/routes/params-ps/non-nested/$foo_/route.tsx b/e2e/react-router/basic-file-based/src/routes/params-ps/non-nested/$foo_/route.tsx index 169655a3cb5..a05ef2993b1 100644 --- a/e2e/react-router/basic-file-based/src/routes/params-ps/non-nested/$foo_/route.tsx +++ b/e2e/react-router/basic-file-based/src/routes/params-ps/non-nested/$foo_/route.tsx @@ -1,9 +1,3 @@ -import { Outlet, createFileRoute } from '@tanstack/react-router' +import { createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/params-ps/non-nested/$foo_')({ - component: RouteComponent, -}) - -function RouteComponent() { - return -} +export const Route = createFileRoute('/params-ps/non-nested/$foo_')() diff --git a/e2e/solid-router/basic-file-based/src/routes/params-ps/non-nested/$foo_/route.tsx b/e2e/solid-router/basic-file-based/src/routes/params-ps/non-nested/$foo_/route.tsx index 96c28d43198..b0611e8627a 100644 --- a/e2e/solid-router/basic-file-based/src/routes/params-ps/non-nested/$foo_/route.tsx +++ b/e2e/solid-router/basic-file-based/src/routes/params-ps/non-nested/$foo_/route.tsx @@ -1,9 +1,3 @@ -import { Outlet, createFileRoute } from '@tanstack/solid-router' +import { createFileRoute } from '@tanstack/solid-router' -export const Route = createFileRoute('/params-ps/non-nested/$foo_')({ - component: RouteComponent, -}) - -function RouteComponent() { - return -} +export const Route = createFileRoute('/params-ps/non-nested/$foo_')() From 8a5da44559c5576d1c40a74b57312f737bb65262 Mon Sep 17 00:00:00 2001 From: Nico Lynzaad Date: Thu, 11 Sep 2025 23:18:53 +0200 Subject: [PATCH 4/4] minor nitpicks from coderabbit --- .../basic-file-based/src/routes/params-ps/non-nested/route.tsx | 2 +- .../basic-file-based/src/routes/params-ps/non-nested/route.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/e2e/react-router/basic-file-based/src/routes/params-ps/non-nested/route.tsx b/e2e/react-router/basic-file-based/src/routes/params-ps/non-nested/route.tsx index 4b5d670d3af..3760bde7088 100644 --- a/e2e/react-router/basic-file-based/src/routes/params-ps/non-nested/route.tsx +++ b/e2e/react-router/basic-file-based/src/routes/params-ps/non-nested/route.tsx @@ -19,8 +19,8 @@ function RouteComponent() { /params-ps/non-nested/$foo/$bar - + ) } diff --git a/e2e/solid-router/basic-file-based/src/routes/params-ps/non-nested/route.tsx b/e2e/solid-router/basic-file-based/src/routes/params-ps/non-nested/route.tsx index 759f6b9a26f..496542c6677 100644 --- a/e2e/solid-router/basic-file-based/src/routes/params-ps/non-nested/route.tsx +++ b/e2e/solid-router/basic-file-based/src/routes/params-ps/non-nested/route.tsx @@ -19,8 +19,8 @@ function RouteComponent() { /params-ps/non-nested/$foo/$bar - + ) }