Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
192 changes: 145 additions & 47 deletions e2e/react-router/basic-file-based/src/routeTree.gen.ts

Large diffs are not rendered by default.

9 changes: 9 additions & 0 deletions e2e/react-router/basic-file-based/src/routes/__root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,15 @@ function RootComponent() {
}}
>
Pathless Layout
</Link>{' '}
<Link
to="/fullpath-test"
data-testid="link-to-fullpath-test"
activeProps={{
className: 'font-bold',
}}
>
FullPath Test
</Link>
</div>
<hr />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { createFileRoute, useMatches } from '@tanstack/react-router'

export const Route = createFileRoute('/fullpath-test/_layout/$id')({
component: IdComponent,
})

function IdComponent() {
const matches = useMatches()
const { id } = Route.useParams()
// Find this route's match by routeId
const idMatch = matches.find(
(m) => m.routeId === '/fullpath-test/_layout/$id',
)

return (
<div>
<div data-testid="param-route-fullpath">
{idMatch?.fullPath ?? 'undefined'}
</div>
<div data-testid="fullpath-test-param">Param: {id}</div>
</div>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { createFileRoute, useMatches } from '@tanstack/react-router'

export const Route = createFileRoute('/fullpath-test/_layout/')({
component: IndexComponent,
})

function IndexComponent() {
const matches = useMatches()
// Find this index route's match by routeId
const indexMatch = matches.find(
(m) => m.routeId === '/fullpath-test/_layout/',
)

return (
<div>
<div data-testid="index-route-fullpath">
{indexMatch?.fullPath ?? 'undefined'}
</div>
<div data-testid="index-route-to">{Route.to}</div>
<div data-testid="fullpath-test-index">FullPath Test Index</div>
</div>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Outlet, createFileRoute, useMatches } from '@tanstack/react-router'

export const Route = createFileRoute('/fullpath-test/_layout')({
component: LayoutComponent,
})

function LayoutComponent() {
const matches = useMatches()
// Find this layout's match by routeId
const layoutMatch = matches.find(
(m) => m.routeId === '/fullpath-test/_layout',
)

return (
<div>
<div data-testid="pathless-layout-fullpath">
{layoutMatch?.fullPath ?? 'undefined'}
</div>
<Outlet />
</div>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Outlet, createFileRoute } from '@tanstack/react-router'

export const Route = createFileRoute('/fullpath-test')({
component: () => (
<div>
<h2 data-testid="fullpath-test-header">FullPath Test Section</h2>
<Outlet />
</div>
),
})
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ function RouteComponent() {
</div>
<div>
<Link
from="/relative/link/path"
from="/relative/link/path/"
to="./$path"
params={{ path: path === 'a' ? 'b' : 'a' }}
className="mr-2"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ function RouteComponent() {
<button
onClick={() =>
navigate({
from: '/relative/useNavigate/path',
from: '/relative/useNavigate/path/',
to: './$path',
params: { path: path === 'a' ? 'b' : 'a' },
})
Expand Down
81 changes: 81 additions & 0 deletions e2e/react-router/basic-file-based/tests/fullpath-types.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { expect, test } from '@playwright/test'

test.describe('FullPath type/runtime match (Issues #4892, #2675, #6403)', () => {
test.describe('Pathless layout routes should have parent fullPath, not empty string', () => {
test('direct navigation to pathless layout shows correct fullPath', async ({
page,
}) => {
await page.goto('/fullpath-test')
// The pathless layout's fullPath should be '/fullpath-test' (same as parent), not ''
await expect(page.getByTestId('pathless-layout-fullpath')).toHaveText(
'/fullpath-test',
)
})

test('client-side navigation to pathless layout shows correct fullPath', async ({
page,
}) => {
await page.goto('/')
await page.getByTestId('link-to-fullpath-test').click()
await expect(page.getByTestId('pathless-layout-fullpath')).toHaveText(
'/fullpath-test',
)
})
})

test.describe('Index routes should have trailing slash in fullPath', () => {
test('direct navigation to index route shows fullPath with trailing slash', async ({
page,
}) => {
await page.goto('/fullpath-test')
// The index route's fullPath should be '/fullpath-test/' (with trailing slash)
await expect(page.getByTestId('index-route-fullpath')).toHaveText(
'/fullpath-test/',
)
})

test('param route under pathless layout shows correct fullPath', async ({
page,
}) => {
await page.goto('/fullpath-test/123')
// The param route's fullPath should be '/fullpath-test/$id'
await expect(page.getByTestId('param-route-fullpath')).toHaveText(
'/fullpath-test/$id',
)
await expect(page.getByTestId('fullpath-test-param')).toHaveText(
'Param: 123',
)
})
})

test.describe('Route.to should NOT have trailing slash (Issue #3005)', () => {
test('index route Route.to should not have trailing slash', async ({
page,
}) => {
await page.goto('/fullpath-test')
// Route.to should be '/fullpath-test' (without trailing slash)
// while Route.fullPath is '/fullpath-test/' (with trailing slash)
await expect(page.getByTestId('index-route-to')).toHaveText(
'/fullpath-test',
)
})
})

test.describe('Existing pathless layout routes', () => {
test('existing pathless layout index shows correct fullPath at runtime', async ({
page,
}) => {
// This tests the existing /pathless-layout route which has a pathless _layout
await page.goto('/pathless-layout')
await expect(page.getByTestId('pathless-layout-header')).toContainText(
'Pathless Layout Section',
)
await expect(page.getByTestId('pathless-layout-wrapper')).toContainText(
'Pathless Layout Wrapper',
)
await expect(page.getByTestId('pathless-layout-index')).toContainText(
'Pathless Layout Index',
)
})
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ declare module '@tanstack/react-router' {
'/_first': {
id: '/_first'
path: ''
fullPath: ''
fullPath: '/'
preLoaderRoute: typeof layoutFirstLayoutRouteImport
parentRoute: typeof rootRouteImport
}
Expand All @@ -199,7 +199,7 @@ declare module '@tanstack/react-router' {
'/_first/_second': {
id: '/_first/_second'
path: ''
fullPath: ''
fullPath: '/'
preLoaderRoute: typeof layoutSecondLayoutRouteImport
parentRoute: typeof layoutFirstLayoutRoute
}
Expand Down
22 changes: 11 additions & 11 deletions e2e/react-start/basic/src/routeTree.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -354,11 +354,11 @@ export interface FileRoutesByFullPath {
'/search-params/default': typeof SearchParamsDefaultRoute
'/search-params/loader-throws-redirect': typeof SearchParamsLoaderThrowsRedirectRoute
'/users/$userId': typeof UsersUserIdRoute
'/multi-cookie-redirect': typeof MultiCookieRedirectIndexRoute
'/multi-cookie-redirect/': typeof MultiCookieRedirectIndexRoute
'/not-found/': typeof NotFoundIndexRoute
'/posts/': typeof PostsIndexRoute
'/raw-stream/': typeof RawStreamIndexRoute
'/redirect': typeof RedirectIndexRoute
'/redirect/': typeof RedirectIndexRoute
'/search-params/': typeof SearchParamsIndexRoute
'/users/': typeof UsersIndexRoute
'/layout-a': typeof LayoutLayout2LayoutARoute
Expand All @@ -372,7 +372,7 @@ export interface FileRoutesByFullPath {
'/redirect/$target/serverFn/via-beforeLoad': typeof RedirectTargetServerFnViaBeforeLoadRoute
'/redirect/$target/serverFn/via-loader': typeof RedirectTargetServerFnViaLoaderRoute
'/redirect/$target/serverFn/via-useServerFn': typeof RedirectTargetServerFnViaUseServerFnRoute
'/redirect/$target/serverFn': typeof RedirectTargetServerFnIndexRoute
'/redirect/$target/serverFn/': typeof RedirectTargetServerFnIndexRoute
'/foo/$bar/$qux/': typeof FooBarQuxHereIndexRoute
}
export interface FileRoutesByTo {
Expand Down Expand Up @@ -505,11 +505,11 @@ export interface FileRouteTypes {
| '/search-params/default'
| '/search-params/loader-throws-redirect'
| '/users/$userId'
| '/multi-cookie-redirect'
| '/multi-cookie-redirect/'
| '/not-found/'
| '/posts/'
| '/raw-stream/'
| '/redirect'
| '/redirect/'
| '/search-params/'
| '/users/'
| '/layout-a'
Expand All @@ -523,7 +523,7 @@ export interface FileRouteTypes {
| '/redirect/$target/serverFn/via-beforeLoad'
| '/redirect/$target/serverFn/via-loader'
| '/redirect/$target/serverFn/via-useServerFn'
| '/redirect/$target/serverFn'
| '/redirect/$target/serverFn/'
| '/foo/$bar/$qux/'
fileRoutesByTo: FileRoutesByTo
to:
Expand Down Expand Up @@ -731,7 +731,7 @@ declare module '@tanstack/react-router' {
'/_layout': {
id: '/_layout'
path: ''
fullPath: ''
fullPath: '/'
preLoaderRoute: typeof LayoutRouteImport
parentRoute: typeof rootRouteImport
}
Expand Down Expand Up @@ -773,7 +773,7 @@ declare module '@tanstack/react-router' {
'/redirect/': {
id: '/redirect/'
path: '/redirect'
fullPath: '/redirect'
fullPath: '/redirect/'
preLoaderRoute: typeof RedirectIndexRouteImport
parentRoute: typeof rootRouteImport
}
Expand Down Expand Up @@ -801,7 +801,7 @@ declare module '@tanstack/react-router' {
'/multi-cookie-redirect/': {
id: '/multi-cookie-redirect/'
path: '/multi-cookie-redirect'
fullPath: '/multi-cookie-redirect'
fullPath: '/multi-cookie-redirect/'
preLoaderRoute: typeof MultiCookieRedirectIndexRouteImport
parentRoute: typeof rootRouteImport
}
Expand Down Expand Up @@ -913,7 +913,7 @@ declare module '@tanstack/react-router' {
'/_layout/_layout-2': {
id: '/_layout/_layout-2'
path: ''
fullPath: ''
fullPath: '/'
preLoaderRoute: typeof LayoutLayout2RouteImport
parentRoute: typeof LayoutRoute
}
Expand Down Expand Up @@ -969,7 +969,7 @@ declare module '@tanstack/react-router' {
'/redirect/$target/serverFn/': {
id: '/redirect/$target/serverFn/'
path: '/serverFn'
fullPath: '/redirect/$target/serverFn'
fullPath: '/redirect/$target/serverFn/'
preLoaderRoute: typeof RedirectTargetServerFnIndexRouteImport
parentRoute: typeof RedirectTargetRoute
}
Expand Down
Loading
Loading