From a69214e528726dffef257c3393466eff837c65d2 Mon Sep 17 00:00:00 2001 From: Birk Skyum Date: Sat, 25 Oct 2025 20:33:51 +0200 Subject: [PATCH 1/3] test(solid): add params.spec.ts to start/router --- e2e/solid-router/basic/tests/params.spec.ts | 149 ++++++++++++++++++++ e2e/solid-start/basic/tests/params.spec.ts | 22 +++ 2 files changed, 171 insertions(+) create mode 100644 e2e/solid-router/basic/tests/params.spec.ts create mode 100644 e2e/solid-start/basic/tests/params.spec.ts diff --git a/e2e/solid-router/basic/tests/params.spec.ts b/e2e/solid-router/basic/tests/params.spec.ts new file mode 100644 index 00000000000..ac18f39864a --- /dev/null +++ b/e2e/solid-router/basic/tests/params.spec.ts @@ -0,0 +1,149 @@ +import { expect, test } from '@playwright/test' + +test.describe('params operations + prefix/suffix', () => { + test.beforeEach(async ({ page }) => { + await page.goto('/params-ps') + }) + + test.describe('named params', () => { + const NAMED_PARAMS_PAIRS = [ + // Test ID | Expected href + { + id: 'l-to-named-foo', + pathname: '/params-ps/named/foo', + params: { foo: 'foo' }, + destHeadingId: 'ParamsNamedFoo', + }, + { + id: 'l-to-named-prefixfoo', + pathname: '/params-ps/named/prefixfoo', + params: { foo: 'foo' }, + destHeadingId: 'ParamsNamedFooPrefix', + }, + { + id: 'l-to-named-foosuffix', + pathname: '/params-ps/named/foosuffix', + params: { foo: 'foo' }, + destHeadingId: 'ParamsNamedFooSuffix', + }, + ] satisfies Array<{ + id: string + pathname: string + params: Record + destHeadingId: string + }> + + test.describe('Link', () => { + NAMED_PARAMS_PAIRS.forEach(({ id, pathname }) => { + test(`interpolation for testid="${id}" has href="${pathname}"`, async ({ + page, + }) => { + const link = page.getByTestId(id) + await expect(link).toHaveAttribute('href', pathname) + }) + }) + + NAMED_PARAMS_PAIRS.forEach(({ id, pathname }) => { + test(`navigation for testid="${id}" succeeds to href="${pathname}"`, async ({ + page, + }) => { + const link = page.getByTestId(id) + await link.click() + await page.waitForLoadState('networkidle') + const pagePathname = new URL(page.url()).pathname + expect(pagePathname).toBe(pathname) + }) + }) + }) + + NAMED_PARAMS_PAIRS.forEach(({ pathname, params, destHeadingId }) => { + test(`on first-load to "${pathname}" has correct params`, async ({ + page, + }) => { + await page.goto(pathname) + await page.waitForLoadState('networkidle') + const pagePathname = new URL(page.url()).pathname + expect(pagePathname).toBe(pathname) + + const headingEl = page.getByRole('heading', { name: destHeadingId }) + await expect(headingEl).toBeVisible() + + const paramsEl = page.getByTestId('params-output') + const paramsText = await paramsEl.innerText() + const paramsObj = JSON.parse(paramsText) + expect(paramsObj).toEqual(params) + }) + }) + }) + + test.describe('wildcard param', () => { + const WILDCARD_PARAM_PAIRS = [ + // Test ID | Expected href + { + id: 'l-to-wildcard-foo', + pathname: '/params-ps/wildcard/foo', + params: { '*': 'foo', _splat: 'foo' }, + destHeadingId: 'ParamsWildcardSplat', + }, + { + id: 'l-to-wildcard-prefixfoo', + pathname: '/params-ps/wildcard/prefixfoo', + params: { '*': 'foo', _splat: 'foo' }, + destHeadingId: 'ParamsWildcardSplatPrefix', + }, + { + id: 'l-to-wildcard-foosuffix', + pathname: '/params-ps/wildcard/foosuffix', + params: { '*': 'foo', _splat: 'foo' }, + destHeadingId: 'ParamsWildcardSplatSuffix', + }, + ] satisfies Array<{ + id: string + pathname: string + params: Record + destHeadingId: string + }> + + test.describe('Link', () => { + WILDCARD_PARAM_PAIRS.forEach(({ id, pathname }) => { + test(`interpolation for testid="${id}" has href="${pathname}"`, async ({ + page, + }) => { + const link = page.getByTestId(id) + await expect(link).toHaveAttribute('href', pathname) + }) + }) + + WILDCARD_PARAM_PAIRS.forEach(({ id, pathname }) => { + test(`navigation for testid="${id}" succeeds to href="${pathname}"`, async ({ + page, + }) => { + const link = page.getByTestId(id) + await link.click() + await page.waitForLoadState('networkidle') + const pagePathname = new URL(page.url()).pathname + expect(pagePathname).toBe(pathname) + }) + }) + }) + + WILDCARD_PARAM_PAIRS.forEach(({ pathname, params, destHeadingId }) => { + test(`on first-load to "${pathname}" has correct params`, async ({ + page, + }) => { + await page.goto(pathname) + await page.waitForLoadState('networkidle') + const pagePathname = new URL(page.url()).pathname + expect(pagePathname).toBe(pathname) + + const headingEl = page.getByRole('heading', { name: destHeadingId }) + await expect(headingEl).toBeVisible() + + const paramsEl = page.getByTestId('params-output') + const paramsText = await paramsEl.innerText() + const paramsObj = JSON.parse(paramsText) + expect(paramsObj).toEqual(params) + }) + }) + }) +}) diff --git a/e2e/solid-start/basic/tests/params.spec.ts b/e2e/solid-start/basic/tests/params.spec.ts new file mode 100644 index 00000000000..737c82f35d2 --- /dev/null +++ b/e2e/solid-start/basic/tests/params.spec.ts @@ -0,0 +1,22 @@ +import { expect } from '@playwright/test' + +import { test } from '@tanstack/router-e2e-utils' + +test.beforeEach(async ({ page }) => { + await page.goto('/') +}) + +test.use({ + whitelistErrors: [ + /Failed to load resource: the server responded with a status of 404/, + ], +}) +test.describe('Unicode route rendering', () => { + test('should render non-latin route correctly', async ({ page, baseURL }) => { + await page.goto('/대한민국') + + await expect(page.locator('body')).toContainText('Hello "/대한민국"!') + + expect(page.url()).toBe(`${baseURL}/%EB%8C%80%ED%95%9C%EB%AF%BC%EA%B5%AD`) + }) +}) From a8e2a6a52d509096a549208315bd5052fb1b3717 Mon Sep 17 00:00:00 2001 From: Birk Skyum Date: Sat, 25 Oct 2025 20:55:19 +0200 Subject: [PATCH 2/3] =?UTF-8?q?add=20=EB=8C=80=ED=95=9C=EB=AF=BC=EA=B5=AD?= =?UTF-8?q?=20routes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../basic-file-based/src/routeTree.gen.ts | 23 +++++++++++++++++++ ...0\355\225\234\353\257\274\352\265\255.tsx" | 9 ++++++++ e2e/solid-start/basic/src/routeTree.gen.ts | 23 +++++++++++++++++++ ...0\355\225\234\353\257\274\352\265\255.tsx" | 9 ++++++++ 4 files changed, 64 insertions(+) create mode 100644 "e2e/solid-router/basic-file-based/src/routes/\353\214\200\355\225\234\353\257\274\352\265\255.tsx" create mode 100644 "e2e/solid-start/basic/src/routes/\353\214\200\355\225\234\353\257\274\352\265\255.tsx" 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 d9f29a8451f..24254a6227a 100644 --- a/e2e/solid-router/basic-file-based/src/routeTree.gen.ts +++ b/e2e/solid-router/basic-file-based/src/routeTree.gen.ts @@ -9,6 +9,7 @@ // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. import { Route as rootRouteImport } from './routes/__root' +import { Route as Char45824Char54620Char48124Char44397RouteImport } from './routes/대한민국' import { Route as RemountDepsRouteImport } from './routes/remountDeps' import { Route as PostsRouteImport } from './routes/posts' import { Route as NotRemountDepsRouteImport } from './routes/notRemountDeps' @@ -88,6 +89,12 @@ import { Route as RelativeLinkPathPathIndexRouteImport } from './routes/relative import { Route as RelativeLinkNestedDeepIndexRouteImport } from './routes/relative/link/nested/deep/index' import { Route as ParamsPsNamedFooBarBazRouteImport } from './routes/params-ps/named/$foo/$bar.$baz' +const Char45824Char54620Char48124Char44397Route = + Char45824Char54620Char48124Char44397RouteImport.update({ + id: '/대한민국', + path: '/대한민국', + getParentRoute: () => rootRouteImport, + } as any) const RemountDepsRoute = RemountDepsRouteImport.update({ id: '/remountDeps', path: '/remountDeps', @@ -514,6 +521,7 @@ export interface FileRoutesByFullPath { '/notRemountDeps': typeof NotRemountDepsRoute '/posts': typeof PostsRouteWithChildren '/remountDeps': typeof RemountDepsRoute + '/대한민국': typeof Char45824Char54620Char48124Char44397Route '/non-nested/named': typeof NonNestedNamedRouteRouteWithChildren '/non-nested/path': typeof NonNestedPathRouteRouteWithChildren '/non-nested/prefix': typeof NonNestedPrefixRouteRouteWithChildren @@ -589,6 +597,7 @@ export interface FileRoutesByTo { '/editing-b': typeof EditingBRoute '/notRemountDeps': typeof NotRemountDepsRoute '/remountDeps': typeof RemountDepsRoute + '/대한민국': typeof Char45824Char54620Char48124Char44397Route '/non-nested/named': typeof NonNestedNamedRouteRouteWithChildren '/non-nested/path': typeof NonNestedPathRouteRouteWithChildren '/non-nested/prefix': typeof NonNestedPrefixRouteRouteWithChildren @@ -663,6 +672,7 @@ export interface FileRoutesById { '/notRemountDeps': typeof NotRemountDepsRoute '/posts': typeof PostsRouteWithChildren '/remountDeps': typeof RemountDepsRoute + '/대한민국': typeof Char45824Char54620Char48124Char44397Route '/non-nested/named': typeof NonNestedNamedRouteRouteWithChildren '/non-nested/path': typeof NonNestedPathRouteRouteWithChildren '/non-nested/prefix': typeof NonNestedPrefixRouteRouteWithChildren @@ -744,6 +754,7 @@ export interface FileRouteTypes { | '/notRemountDeps' | '/posts' | '/remountDeps' + | '/대한민국' | '/non-nested/named' | '/non-nested/path' | '/non-nested/prefix' @@ -819,6 +830,7 @@ export interface FileRouteTypes { | '/editing-b' | '/notRemountDeps' | '/remountDeps' + | '/대한민국' | '/non-nested/named' | '/non-nested/path' | '/non-nested/prefix' @@ -892,6 +904,7 @@ export interface FileRouteTypes { | '/notRemountDeps' | '/posts' | '/remountDeps' + | '/대한민국' | '/non-nested/named' | '/non-nested/path' | '/non-nested/prefix' @@ -973,6 +986,7 @@ export interface RootRouteChildren { NotRemountDepsRoute: typeof NotRemountDepsRoute PostsRoute: typeof PostsRouteWithChildren RemountDepsRoute: typeof RemountDepsRoute + Char45824Char54620Char48124Char44397Route: typeof Char45824Char54620Char48124Char44397Route ParamsPsNonNestedRouteRoute: typeof ParamsPsNonNestedRouteRouteWithChildren RelativeLinkRouteRoute: typeof RelativeLinkRouteRouteWithChildren RelativeUseNavigateRouteRoute: typeof RelativeUseNavigateRouteRouteWithChildren @@ -995,6 +1009,13 @@ export interface RootRouteChildren { declare module '@tanstack/solid-router' { interface FileRoutesByPath { + '/대한민국': { + id: '/대한민국' + path: '/대한민국' + fullPath: '/대한민국' + preLoaderRoute: typeof Char45824Char54620Char48124Char44397RouteImport + parentRoute: typeof rootRouteImport + } '/remountDeps': { id: '/remountDeps' path: '/remountDeps' @@ -1884,6 +1905,8 @@ const rootRouteChildren: RootRouteChildren = { NotRemountDepsRoute: NotRemountDepsRoute, PostsRoute: PostsRouteWithChildren, RemountDepsRoute: RemountDepsRoute, + Char45824Char54620Char48124Char44397Route: + Char45824Char54620Char48124Char44397Route, ParamsPsNonNestedRouteRoute: ParamsPsNonNestedRouteRouteWithChildren, RelativeLinkRouteRoute: RelativeLinkRouteRouteWithChildren, RelativeUseNavigateRouteRoute: RelativeUseNavigateRouteRouteWithChildren, diff --git "a/e2e/solid-router/basic-file-based/src/routes/\353\214\200\355\225\234\353\257\274\352\265\255.tsx" "b/e2e/solid-router/basic-file-based/src/routes/\353\214\200\355\225\234\353\257\274\352\265\255.tsx" new file mode 100644 index 00000000000..897c0576cc4 --- /dev/null +++ "b/e2e/solid-router/basic-file-based/src/routes/\353\214\200\355\225\234\353\257\274\352\265\255.tsx" @@ -0,0 +1,9 @@ +import { createFileRoute } from '@tanstack/solid-router' + +export const Route = createFileRoute('/대한민국')({ + component: RouteComponent, +}) + +function RouteComponent() { + return
Hello "/대한민국"!
+} diff --git a/e2e/solid-start/basic/src/routeTree.gen.ts b/e2e/solid-start/basic/src/routeTree.gen.ts index 9bbb8755f9c..aac25901997 100644 --- a/e2e/solid-start/basic/src/routeTree.gen.ts +++ b/e2e/solid-start/basic/src/routeTree.gen.ts @@ -9,6 +9,7 @@ // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. import { Route as rootRouteImport } from './routes/__root' +import { Route as Char45824Char54620Char48124Char44397RouteImport } from './routes/대한민국' import { Route as UsersRouteImport } from './routes/users' import { Route as StreamRouteImport } from './routes/stream' import { Route as ScriptsRouteImport } from './routes/scripts' @@ -46,6 +47,12 @@ import { Route as RedirectTargetServerFnViaUseServerFnRouteImport } from './rout import { Route as RedirectTargetServerFnViaLoaderRouteImport } from './routes/redirect/$target/serverFn/via-loader' import { Route as RedirectTargetServerFnViaBeforeLoadRouteImport } from './routes/redirect/$target/serverFn/via-beforeLoad' +const Char45824Char54620Char48124Char44397Route = + Char45824Char54620Char48124Char44397RouteImport.update({ + id: '/대한민국', + path: '/대한민국', + getParentRoute: () => rootRouteImport, + } as any) const UsersRoute = UsersRouteImport.update({ id: '/users', path: '/users', @@ -242,6 +249,7 @@ export interface FileRoutesByFullPath { '/scripts': typeof ScriptsRoute '/stream': typeof StreamRoute '/users': typeof UsersRouteWithChildren + '/대한민국': typeof Char45824Char54620Char48124Char44397Route '/api/users': typeof ApiUsersRouteWithChildren '/not-found/via-beforeLoad': typeof NotFoundViaBeforeLoadRoute '/not-found/via-loader': typeof NotFoundViaLoaderRoute @@ -274,6 +282,7 @@ export interface FileRoutesByTo { '/links': typeof LinksRoute '/scripts': typeof ScriptsRoute '/stream': typeof StreamRoute + '/대한민국': typeof Char45824Char54620Char48124Char44397Route '/api/users': typeof ApiUsersRouteWithChildren '/not-found/via-beforeLoad': typeof NotFoundViaBeforeLoadRoute '/not-found/via-loader': typeof NotFoundViaLoaderRoute @@ -311,6 +320,7 @@ export interface FileRoutesById { '/scripts': typeof ScriptsRoute '/stream': typeof StreamRoute '/users': typeof UsersRouteWithChildren + '/대한민국': typeof Char45824Char54620Char48124Char44397Route '/_layout/_layout-2': typeof LayoutLayout2RouteWithChildren '/api/users': typeof ApiUsersRouteWithChildren '/not-found/via-beforeLoad': typeof NotFoundViaBeforeLoadRoute @@ -350,6 +360,7 @@ export interface FileRouteTypes { | '/scripts' | '/stream' | '/users' + | '/대한민국' | '/api/users' | '/not-found/via-beforeLoad' | '/not-found/via-loader' @@ -382,6 +393,7 @@ export interface FileRouteTypes { | '/links' | '/scripts' | '/stream' + | '/대한민국' | '/api/users' | '/not-found/via-beforeLoad' | '/not-found/via-loader' @@ -418,6 +430,7 @@ export interface FileRouteTypes { | '/scripts' | '/stream' | '/users' + | '/대한민국' | '/_layout/_layout-2' | '/api/users' | '/not-found/via-beforeLoad' @@ -457,6 +470,7 @@ export interface RootRouteChildren { ScriptsRoute: typeof ScriptsRoute StreamRoute: typeof StreamRoute UsersRoute: typeof UsersRouteWithChildren + Char45824Char54620Char48124Char44397Route: typeof Char45824Char54620Char48124Char44397Route ApiUsersRoute: typeof ApiUsersRouteWithChildren RedirectTargetRoute: typeof RedirectTargetRouteWithChildren RedirectIndexRoute: typeof RedirectIndexRoute @@ -465,6 +479,13 @@ export interface RootRouteChildren { declare module '@tanstack/solid-router' { interface FileRoutesByPath { + '/대한민국': { + id: '/대한민국' + path: '/대한민국' + fullPath: '/대한민국' + preLoaderRoute: typeof Char45824Char54620Char48124Char44397RouteImport + parentRoute: typeof rootRouteImport + } '/users': { id: '/users' path: '/users' @@ -850,6 +871,8 @@ const rootRouteChildren: RootRouteChildren = { ScriptsRoute: ScriptsRoute, StreamRoute: StreamRoute, UsersRoute: UsersRouteWithChildren, + Char45824Char54620Char48124Char44397Route: + Char45824Char54620Char48124Char44397Route, ApiUsersRoute: ApiUsersRouteWithChildren, RedirectTargetRoute: RedirectTargetRouteWithChildren, RedirectIndexRoute: RedirectIndexRoute, diff --git "a/e2e/solid-start/basic/src/routes/\353\214\200\355\225\234\353\257\274\352\265\255.tsx" "b/e2e/solid-start/basic/src/routes/\353\214\200\355\225\234\353\257\274\352\265\255.tsx" new file mode 100644 index 00000000000..897c0576cc4 --- /dev/null +++ "b/e2e/solid-start/basic/src/routes/\353\214\200\355\225\234\353\257\274\352\265\255.tsx" @@ -0,0 +1,9 @@ +import { createFileRoute } from '@tanstack/solid-router' + +export const Route = createFileRoute('/대한민국')({ + component: RouteComponent, +}) + +function RouteComponent() { + return
Hello "/대한민국"!
+} From 3459ec046cf389b3fb5dd7ac8bdd017900a204e2 Mon Sep 17 00:00:00 2001 From: Birk Skyum Date: Sat, 25 Oct 2025 21:57:32 +0200 Subject: [PATCH 3/3] add params routes --- e2e/solid-router/basic/src/main.tsx | 203 ++++++++++++++++++++++++++++ 1 file changed, 203 insertions(+) diff --git a/e2e/solid-router/basic/src/main.tsx b/e2e/solid-router/basic/src/main.tsx index 9bb8b6f8e4a..4005b95067f 100644 --- a/e2e/solid-router/basic/src/main.tsx +++ b/e2e/solid-router/basic/src/main.tsx @@ -8,6 +8,7 @@ import { createRootRoute, createRoute, createRouter, + redirect, } from '@tanstack/solid-router' import { TanStackRouterDevtools } from '@tanstack/solid-router-devtools' import { NotFoundError, fetchPost, fetchPosts } from './posts' @@ -207,11 +208,213 @@ function LayoutBComponent() { return
I'm layout B!
} +const paramsPsRoute = createRoute({ + getParentRoute: () => rootRoute, + path: '/params-ps', +}) + +const paramsPsIndexRoute = createRoute({ + getParentRoute: () => paramsPsRoute, + path: '/', + component: function ParamsIndex() { + return ( +
+

Named path params

+
    +
  • + + /params-ps/named/$foo + +
  • +
  • + + /params-ps/named/{'prefix{$foo}'} + +
  • +
  • + + /params-ps/named/{'{$foo}suffix'} + +
  • +
+
+

Wildcard path params

+
    +
  • + + /params-ps/wildcard/$ + +
  • +
  • + + /params-ps/wildcard/{'prefix{$}'} + +
  • +
  • + + /params-ps/wildcard/{'{$}suffix'} + +
  • +
+
+ ) + }, +}) + +const paramsPsNamedRoute = createRoute({ + getParentRoute: () => paramsPsRoute, + path: '/named', +}) + +const paramsPsNamedIndexRoute = createRoute({ + getParentRoute: () => paramsPsNamedRoute, + path: '/', + beforeLoad: () => { + throw redirect({ to: '/params-ps' }) + }, +}) + +const paramsPsNamedFooRoute = createRoute({ + getParentRoute: () => paramsPsNamedRoute, + path: '/$foo', + component: function ParamsNamedFoo() { + const p = paramsPsNamedFooRoute.useParams() + return ( +
+

ParamsNamedFoo

+
{JSON.stringify(p())}
+
+ ) + }, +}) + +const paramsPsNamedFooPrefixRoute = createRoute({ + getParentRoute: () => paramsPsNamedRoute, + path: '/prefix{$foo}', + component: function ParamsNamedFooMarkdown() { + const p = paramsPsNamedFooPrefixRoute.useParams() + return ( +
+

ParamsNamedFooPrefix

+
{JSON.stringify(p())}
+
+ ) + }, +}) + +const paramsPsNamedFooSuffixRoute = createRoute({ + getParentRoute: () => paramsPsNamedRoute, + path: '/{$foo}suffix', + component: function ParamsNamedFooSuffix() { + const p = paramsPsNamedFooSuffixRoute.useParams() + return ( +
+

ParamsNamedFooSuffix

+
{JSON.stringify(p())}
+
+ ) + }, +}) + +const paramsPsWildcardRoute = createRoute({ + getParentRoute: () => paramsPsRoute, + path: '/wildcard', +}) + +const paramsPsWildcardIndexRoute = createRoute({ + getParentRoute: () => paramsPsWildcardRoute, + path: '/', + beforeLoad: () => { + throw redirect({ to: '/params-ps' }) + }, +}) + +const paramsPsWildcardSplatRoute = createRoute({ + getParentRoute: () => paramsPsWildcardRoute, + path: '$', + component: function ParamsWildcardSplat() { + const p = paramsPsWildcardSplatRoute.useParams() + return ( +
+

ParamsWildcardSplat

+
{JSON.stringify(p())}
+
+ ) + }, +}) + +const paramsPsWildcardSplatPrefixRoute = createRoute({ + getParentRoute: () => paramsPsWildcardRoute, + path: 'prefix{$}', + component: function ParamsWildcardSplatPrefix() { + const p = paramsPsWildcardSplatPrefixRoute.useParams() + return ( +
+

ParamsWildcardSplatPrefix

+
{JSON.stringify(p())}
+
+ ) + }, +}) + +const paramsPsWildcardSplatSuffixRoute = createRoute({ + getParentRoute: () => paramsPsWildcardRoute, + path: '{$}suffix', + component: function ParamsWildcardSplatSuffix() { + const p = paramsPsWildcardSplatSuffixRoute.useParams() + return ( +
+

ParamsWildcardSplatSuffix

+
{JSON.stringify(p())}
+
+ ) + }, +}) + const routeTree = rootRoute.addChildren([ postsRoute.addChildren([postRoute, postsIndexRoute]), layoutRoute.addChildren([ layout2Route.addChildren([layoutARoute, layoutBRoute]), ]), + paramsPsRoute.addChildren([ + paramsPsNamedRoute.addChildren([ + paramsPsNamedFooPrefixRoute, + paramsPsNamedFooSuffixRoute, + paramsPsNamedFooRoute, + paramsPsNamedIndexRoute, + ]), + paramsPsWildcardRoute.addChildren([ + paramsPsWildcardSplatRoute, + paramsPsWildcardSplatPrefixRoute, + paramsPsWildcardSplatSuffixRoute, + paramsPsWildcardIndexRoute, + ]), + paramsPsIndexRoute, + ]), indexRoute, ])