diff --git a/e2e/start/basic/app/routes/nested-docs.$project.$version.docs.framework.$framework.$.tsx b/e2e/start/basic/app/routes/nested-docs.$project.$version.docs.framework.$framework.$.tsx deleted file mode 100644 index 7551b6e5aa..0000000000 --- a/e2e/start/basic/app/routes/nested-docs.$project.$version.docs.framework.$framework.$.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import { ErrorComponent, createFileRoute } from '@tanstack/react-router' -import type { ErrorComponentProps } from '@tanstack/react-router' -import { NotFound } from '~/components/NotFound' -import { fetchPost } from '~/utils/posts' - -export const Route = createFileRoute( - '/nested-docs/$project/$version/docs/framework/$framework/$', -)({ - loader: ({ params: { _splat } }) => { - console.debug('👀 params._splat', _splat) - return fetchPost(_splat!) - }, - errorComponent: PostErrorComponent, - component: Page, - notFoundComponent: () => { - return Post not found - }, -}) - -function PostErrorComponent({ error }: ErrorComponentProps) { - return -} - -function Page() { - const post = Route.useLoaderData() - - return ( -
-

- Heading for ID = {post.id} -

-
{post.body}
-
- ) -} diff --git a/e2e/start/basic/app/routes/nested-docs.$project.$version.docs.framework.$framework.index.tsx b/e2e/start/basic/app/routes/nested-docs.$project.$version.docs.framework.$framework.index.tsx deleted file mode 100644 index e1cdec0d96..0000000000 --- a/e2e/start/basic/app/routes/nested-docs.$project.$version.docs.framework.$framework.index.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute( - '/nested-docs/$project/$version/docs/framework/$framework/', -)({ - component: () =>
Selected a post by it's ID.
, -}) diff --git a/e2e/start/basic/app/routes/nested-docs.$project.$version.docs.framework.$framework.tsx b/e2e/start/basic/app/routes/nested-docs.$project.$version.docs.framework.$framework.tsx deleted file mode 100644 index e2aac7f9ce..0000000000 --- a/e2e/start/basic/app/routes/nested-docs.$project.$version.docs.framework.$framework.tsx +++ /dev/null @@ -1,147 +0,0 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/react-router' -import { fetchPosts } from '~/utils/posts' - -export const Route = createFileRoute( - '/nested-docs/$project/$version/docs/framework/$framework', -)({ - loader: () => fetchPosts(), - component: Page, -}) - -function Page() { - const posts = Route.useLoaderData() - const params = Route.useParams() - - return ( - <> -
- Select project - -
-
- Select version - -
-
- Select framework - -
-

- Selected: - - /nested-docs/{params.project}/{params.version}/docs/framework/ - {params.framework} - -

-
- -
- -
- - ) -} diff --git a/e2e/start/basic/app/routes/nested-docs.$project.$version.index.tsx b/e2e/start/basic/app/routes/nested-docs.$project.$version.index.tsx deleted file mode 100644 index 4a19e47725..0000000000 --- a/e2e/start/basic/app/routes/nested-docs.$project.$version.index.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import { createFileRoute, redirect } from '@tanstack/react-router' - -export const Route = createFileRoute('/nested-docs/$project/$version/')({ - loader: ({ params }) => { - throw redirect({ - from: '/nested-docs/$project/$version', - to: '/nested-docs/$project/$version/docs/framework/$framework', - params: { - project: params.project, - version: params.version, - framework: 'react', - }, - }) - }, - component: () =>
Hello /nested-docs/$project/$version/!
, -}) diff --git a/e2e/start/basic/app/routes/nested-docs.$project.index.tsx b/e2e/start/basic/app/routes/nested-docs.$project.index.tsx deleted file mode 100644 index b48b584457..0000000000 --- a/e2e/start/basic/app/routes/nested-docs.$project.index.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { createFileRoute, redirect } from '@tanstack/react-router' - -export const Route = createFileRoute('/nested-docs/$project/')({ - loader: ({ params }) => { - throw redirect({ - to: '/nested-docs/$project/$version/docs/framework/$framework', - params: { - project: params.project, - version: 'latest', - framework: 'react', - }, - }) - }, - component: () =>
Hello /nested-docs/$project/!
, -}) diff --git a/e2e/start/basic/app/routes/nested-docs.index.tsx b/e2e/start/basic/app/routes/nested-docs.index.tsx deleted file mode 100644 index 3bd21cbc08..0000000000 --- a/e2e/start/basic/app/routes/nested-docs.index.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import { createFileRoute, redirect } from '@tanstack/react-router' - -export const Route = createFileRoute('/nested-docs/')({ - loader: () => { - throw redirect({ - to: '/nested-docs/$project/$version/docs/framework/$framework', - params: { project: 'router', version: 'latest', framework: 'react' }, - }) - }, - component: () =>
Hello /nested-docs/!
, -}) diff --git a/e2e/start/basic/app/routes/nested-docs.tsx b/e2e/start/basic/app/routes/nested-docs.tsx deleted file mode 100644 index 5ae416c552..0000000000 --- a/e2e/start/basic/app/routes/nested-docs.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import { Outlet, createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/nested-docs')({ - component: () => ( -
- -
- ), -}) diff --git a/e2e/start/basic/tests/docs-layout.spec.ts b/e2e/start/basic/tests/docs-layout.spec.ts deleted file mode 100644 index c6f829447a..0000000000 --- a/e2e/start/basic/tests/docs-layout.spec.ts +++ /dev/null @@ -1,119 +0,0 @@ -import { expect, test } from '@playwright/test' - -const routeTestId = 'selected-route-label' - -test('index redirect resolves', async ({ page }) => { - await page.goto('/nested-docs') - - await expect(page.getByTestId(routeTestId)).toContainText( - '/nested-docs/router/latest/docs/framework/react', - ) -}) - -test('can change the project', async ({ page }) => { - await page.goto('/nested-docs') - await page.getByRole('link', { name: 'Query' }).click() - - await expect(page.getByTestId(routeTestId)).toContainText( - '/nested-docs/query/latest/docs/framework/react', - ) -}) - -test('can change the version', async ({ page }) => { - await page.goto('/nested-docs') - await page.getByRole('link', { name: 'V1' }).click() - - await expect(page.getByTestId(routeTestId)).toContainText( - '/nested-docs/router/v1/docs/framework/react', - ) -}) - -test('can change the framework', async ({ page }) => { - await page.goto('/nested-docs') - await page.getByRole('link', { name: 'SolidJS' }).click() - - await expect(page.getByTestId(routeTestId)).toContainText( - '/nested-docs/router/latest/docs/framework/solidjs', - ) -}) - -test('navigate to post 1', async ({ page }) => { - await page.goto('/nested-docs') - await page.getByRole('link', { name: 'Post ID = 1', exact: true }).click() - - await expect(page.getByRole('heading')).toContainText('Heading for ID = 1') -}) - -test('change project from post 1', async ({ page }) => { - await page.goto('/nested-docs/router/latest/docs/framework/react/1') - await expect(page.getByRole('heading')).toContainText('Heading for ID = 1') - await page.getByRole('link', { name: 'Query' }).click() - - await expect(page.getByTestId(routeTestId)).toContainText( - '/nested-docs/query/latest/docs/framework/react', - ) -}) - -test('change version from post 1', async ({ page }) => { - await page.goto('/nested-docs/router/latest/docs/framework/react/1') - await expect(page.getByRole('heading')).toContainText('Heading for ID = 1') - await page.getByRole('link', { name: 'V2' }).click() - - await expect(page.getByTestId(routeTestId)).toContainText( - '/nested-docs/router/v2/docs/framework/react', - ) -}) - -test('change framework from post 1', async ({ page }) => { - await page.goto('/nested-docs/router/latest/docs/framework/react/1') - await expect(page.getByRole('heading')).toContainText('Heading for ID = 1') - await page.getByRole('link', { name: 'SolidJS' }).click() - - await expect(page.getByTestId(routeTestId)).toContainText( - '/nested-docs/router/latest/docs/framework/solidjs', - ) -}) - -test('can change project,version,framework from root', async ({ page }) => { - await page.goto('/nested-docs') - await expect(page.getByTestId(routeTestId)).toContainText( - '/nested-docs/router/latest/docs/framework/react', - ) - - await page.getByRole('link', { name: 'Query' }).click() - await expect(page.getByTestId(routeTestId)).toContainText( - '/nested-docs/query/latest/docs/framework/react', - ) - - await page.getByRole('link', { name: 'V2' }).click() - await expect(page.getByTestId(routeTestId)).toContainText( - '/nested-docs/query/v2/docs/framework/react', - ) - - await page.getByRole('link', { name: 'SolidJS' }).click() - await expect(page.getByTestId(routeTestId)).toContainText( - '/nested-docs/query/v2/docs/framework/solidjs', - ) -}) - -test('can change project,version,framework from post 1', async ({ page }) => { - await page.goto('/nested-docs/router/latest/docs/framework/react/1') - await expect(page.getByTestId(routeTestId)).toContainText( - '/nested-docs/router/latest/docs/framework/react', - ) - - await page.getByRole('link', { name: 'Query' }).click() - await expect(page.getByTestId(routeTestId)).toContainText( - '/nested-docs/query/latest/docs/framework/react', - ) - - await page.getByRole('link', { name: 'V2' }).click() - await expect(page.getByTestId(routeTestId)).toContainText( - '/nested-docs/query/v2/docs/framework/react', - ) - - await page.getByRole('link', { name: 'SolidJS' }).click() - await expect(page.getByTestId(routeTestId)).toContainText( - '/nested-docs/query/v2/docs/framework/solidjs', - ) -}) diff --git a/e2e/start/website/.gitignore b/e2e/start/website/.gitignore new file mode 100644 index 0000000000..be342025da --- /dev/null +++ b/e2e/start/website/.gitignore @@ -0,0 +1,22 @@ +node_modules +package-lock.json +yarn.lock + +.DS_Store +.cache +.env +.vercel +.output +.vinxi + +/build/ +/api/ +/server/build +/public/build +.vinxi +# Sentry Config File +.env.sentry-build-plugin +/test-results/ +/playwright-report/ +/blob-report/ +/playwright/.cache/ diff --git a/e2e/start/website/.prettierignore b/e2e/start/website/.prettierignore new file mode 100644 index 0000000000..2be5eaa6ec --- /dev/null +++ b/e2e/start/website/.prettierignore @@ -0,0 +1,4 @@ +**/build +**/public +pnpm-lock.yaml +routeTree.gen.ts \ No newline at end of file diff --git a/e2e/start/website/app.config.ts b/e2e/start/website/app.config.ts new file mode 100644 index 0000000000..732f04eabe --- /dev/null +++ b/e2e/start/website/app.config.ts @@ -0,0 +1,12 @@ +import { defineConfig } from '@tanstack/start/config' +import tsConfigPaths from 'vite-tsconfig-paths' + +export default defineConfig({ + vite: { + plugins: [ + tsConfigPaths({ + projects: ['./tsconfig.json'], + }), + ], + }, +}) diff --git a/e2e/start/website/app/client.tsx b/e2e/start/website/app/client.tsx new file mode 100644 index 0000000000..7bde1ff01e --- /dev/null +++ b/e2e/start/website/app/client.tsx @@ -0,0 +1,8 @@ +/// +import { hydrateRoot } from 'react-dom/client' +import { StartClient } from '@tanstack/start' +import { createRouter } from './router' + +const router = createRouter() + +hydrateRoot(document.getElementById('root')!, ) diff --git a/e2e/start/website/app/components/DefaultCatchBoundary.tsx b/e2e/start/website/app/components/DefaultCatchBoundary.tsx new file mode 100644 index 0000000000..15f316681c --- /dev/null +++ b/e2e/start/website/app/components/DefaultCatchBoundary.tsx @@ -0,0 +1,53 @@ +import { + ErrorComponent, + Link, + rootRouteId, + useMatch, + useRouter, +} from '@tanstack/react-router' +import type { ErrorComponentProps } from '@tanstack/react-router' + +export function DefaultCatchBoundary({ error }: ErrorComponentProps) { + const router = useRouter() + const isRoot = useMatch({ + strict: false, + select: (state) => state.id === rootRouteId, + }) + + console.error(error) + + return ( +
+ +
+ + {isRoot ? ( + + Home + + ) : ( + { + e.preventDefault() + window.history.back() + }} + > + Go Back + + )} +
+
+ ) +} diff --git a/e2e/start/website/app/components/NotFound.tsx b/e2e/start/website/app/components/NotFound.tsx new file mode 100644 index 0000000000..7b54fa5680 --- /dev/null +++ b/e2e/start/website/app/components/NotFound.tsx @@ -0,0 +1,25 @@ +import { Link } from '@tanstack/react-router' + +export function NotFound({ children }: { children?: any }) { + return ( +
+
+ {children ||

The page you are looking for does not exist.

} +
+

+ + + Start Over + +

+
+ ) +} diff --git a/e2e/start/website/app/routeTree.gen.ts b/e2e/start/website/app/routeTree.gen.ts new file mode 100644 index 0000000000..149847ed30 --- /dev/null +++ b/e2e/start/website/app/routeTree.gen.ts @@ -0,0 +1,372 @@ +/* prettier-ignore-start */ + +/* eslint-disable */ + +// @ts-nocheck + +// noinspection JSUnusedGlobalSymbols + +// This file is auto-generated by TanStack Router + +// Import Routes + +import { Route as rootRoute } from './routes/__root' +import { Route as LibraryImport } from './routes/_library' +import { Route as LibraryIndexImport } from './routes/_library.index' +import { Route as ProjectIndexImport } from './routes/$project.index' +import { Route as LibraryProjectImport } from './routes/_library.$project' +import { Route as LibraryProjectVersionIndexImport } from './routes/_library.$project.$version.index' +import { Route as ProjectVersionDocsIndexImport } from './routes/$project.$version.docs.index' +import { Route as ProjectVersionDocsFrameworkFrameworkImport } from './routes/$project.$version.docs.framework.$framework' +import { Route as ProjectVersionDocsFrameworkFrameworkIndexImport } from './routes/$project.$version.docs.framework.$framework.index' +import { Route as ProjectVersionDocsFrameworkFrameworkSplatImport } from './routes/$project.$version.docs.framework.$framework.$' +import { Route as ProjectVersionDocsFrameworkFrameworkExamplesSplatImport } from './routes/$project.$version.docs.framework.$framework.examples.$' + +// Create/Update Routes + +const LibraryRoute = LibraryImport.update({ + id: '/_library', + getParentRoute: () => rootRoute, +} as any) + +const LibraryIndexRoute = LibraryIndexImport.update({ + id: '/', + path: '/', + getParentRoute: () => LibraryRoute, +} as any) + +const ProjectIndexRoute = ProjectIndexImport.update({ + id: '/$project/', + path: '/$project/', + getParentRoute: () => rootRoute, +} as any) + +const LibraryProjectRoute = LibraryProjectImport.update({ + id: '/$project', + path: '/$project', + getParentRoute: () => LibraryRoute, +} as any) + +const LibraryProjectVersionIndexRoute = LibraryProjectVersionIndexImport.update( + { + id: '/$version/', + path: '/$version/', + getParentRoute: () => LibraryProjectRoute, + } as any, +) + +const ProjectVersionDocsIndexRoute = ProjectVersionDocsIndexImport.update({ + id: '/$project/$version/docs/', + path: '/$project/$version/docs/', + getParentRoute: () => rootRoute, +} as any) + +const ProjectVersionDocsFrameworkFrameworkRoute = + ProjectVersionDocsFrameworkFrameworkImport.update({ + id: '/$project/$version/docs/framework/$framework', + path: '/$project/$version/docs/framework/$framework', + getParentRoute: () => rootRoute, + } as any) + +const ProjectVersionDocsFrameworkFrameworkIndexRoute = + ProjectVersionDocsFrameworkFrameworkIndexImport.update({ + id: '/', + path: '/', + getParentRoute: () => ProjectVersionDocsFrameworkFrameworkRoute, + } as any) + +const ProjectVersionDocsFrameworkFrameworkSplatRoute = + ProjectVersionDocsFrameworkFrameworkSplatImport.update({ + id: '/$', + path: '/$', + getParentRoute: () => ProjectVersionDocsFrameworkFrameworkRoute, + } as any) + +const ProjectVersionDocsFrameworkFrameworkExamplesSplatRoute = + ProjectVersionDocsFrameworkFrameworkExamplesSplatImport.update({ + id: '/examples/$', + path: '/examples/$', + getParentRoute: () => ProjectVersionDocsFrameworkFrameworkRoute, + } as any) + +// Populate the FileRoutesByPath interface + +declare module '@tanstack/react-router' { + interface FileRoutesByPath { + '/_library': { + id: '/_library' + path: '' + fullPath: '' + preLoaderRoute: typeof LibraryImport + parentRoute: typeof rootRoute + } + '/_library/$project': { + id: '/_library/$project' + path: '/$project' + fullPath: '/$project' + preLoaderRoute: typeof LibraryProjectImport + parentRoute: typeof LibraryImport + } + '/$project/': { + id: '/$project/' + path: '/$project' + fullPath: '/$project' + preLoaderRoute: typeof ProjectIndexImport + parentRoute: typeof rootRoute + } + '/_library/': { + id: '/_library/' + path: '/' + fullPath: '/' + preLoaderRoute: typeof LibraryIndexImport + parentRoute: typeof LibraryImport + } + '/$project/$version/docs/': { + id: '/$project/$version/docs/' + path: '/$project/$version/docs' + fullPath: '/$project/$version/docs' + preLoaderRoute: typeof ProjectVersionDocsIndexImport + parentRoute: typeof rootRoute + } + '/_library/$project/$version/': { + id: '/_library/$project/$version/' + path: '/$version' + fullPath: '/$project/$version' + preLoaderRoute: typeof LibraryProjectVersionIndexImport + parentRoute: typeof LibraryProjectImport + } + '/$project/$version/docs/framework/$framework': { + id: '/$project/$version/docs/framework/$framework' + path: '/$project/$version/docs/framework/$framework' + fullPath: '/$project/$version/docs/framework/$framework' + preLoaderRoute: typeof ProjectVersionDocsFrameworkFrameworkImport + parentRoute: typeof rootRoute + } + '/$project/$version/docs/framework/$framework/$': { + id: '/$project/$version/docs/framework/$framework/$' + path: '/$' + fullPath: '/$project/$version/docs/framework/$framework/$' + preLoaderRoute: typeof ProjectVersionDocsFrameworkFrameworkSplatImport + parentRoute: typeof ProjectVersionDocsFrameworkFrameworkImport + } + '/$project/$version/docs/framework/$framework/': { + id: '/$project/$version/docs/framework/$framework/' + path: '/' + fullPath: '/$project/$version/docs/framework/$framework/' + preLoaderRoute: typeof ProjectVersionDocsFrameworkFrameworkIndexImport + parentRoute: typeof ProjectVersionDocsFrameworkFrameworkImport + } + '/$project/$version/docs/framework/$framework/examples/$': { + id: '/$project/$version/docs/framework/$framework/examples/$' + path: '/examples/$' + fullPath: '/$project/$version/docs/framework/$framework/examples/$' + preLoaderRoute: typeof ProjectVersionDocsFrameworkFrameworkExamplesSplatImport + parentRoute: typeof ProjectVersionDocsFrameworkFrameworkImport + } + } +} + +// Create and export the route tree + +interface LibraryProjectRouteChildren { + LibraryProjectVersionIndexRoute: typeof LibraryProjectVersionIndexRoute +} + +const LibraryProjectRouteChildren: LibraryProjectRouteChildren = { + LibraryProjectVersionIndexRoute: LibraryProjectVersionIndexRoute, +} + +const LibraryProjectRouteWithChildren = LibraryProjectRoute._addFileChildren( + LibraryProjectRouteChildren, +) + +interface LibraryRouteChildren { + LibraryProjectRoute: typeof LibraryProjectRouteWithChildren + LibraryIndexRoute: typeof LibraryIndexRoute +} + +const LibraryRouteChildren: LibraryRouteChildren = { + LibraryProjectRoute: LibraryProjectRouteWithChildren, + LibraryIndexRoute: LibraryIndexRoute, +} + +const LibraryRouteWithChildren = + LibraryRoute._addFileChildren(LibraryRouteChildren) + +interface ProjectVersionDocsFrameworkFrameworkRouteChildren { + ProjectVersionDocsFrameworkFrameworkSplatRoute: typeof ProjectVersionDocsFrameworkFrameworkSplatRoute + ProjectVersionDocsFrameworkFrameworkIndexRoute: typeof ProjectVersionDocsFrameworkFrameworkIndexRoute + ProjectVersionDocsFrameworkFrameworkExamplesSplatRoute: typeof ProjectVersionDocsFrameworkFrameworkExamplesSplatRoute +} + +const ProjectVersionDocsFrameworkFrameworkRouteChildren: ProjectVersionDocsFrameworkFrameworkRouteChildren = + { + ProjectVersionDocsFrameworkFrameworkSplatRoute: + ProjectVersionDocsFrameworkFrameworkSplatRoute, + ProjectVersionDocsFrameworkFrameworkIndexRoute: + ProjectVersionDocsFrameworkFrameworkIndexRoute, + ProjectVersionDocsFrameworkFrameworkExamplesSplatRoute: + ProjectVersionDocsFrameworkFrameworkExamplesSplatRoute, + } + +const ProjectVersionDocsFrameworkFrameworkRouteWithChildren = + ProjectVersionDocsFrameworkFrameworkRoute._addFileChildren( + ProjectVersionDocsFrameworkFrameworkRouteChildren, + ) + +export interface FileRoutesByFullPath { + '': typeof LibraryRouteWithChildren + '/$project': typeof ProjectIndexRoute + '/': typeof LibraryIndexRoute + '/$project/$version/docs': typeof ProjectVersionDocsIndexRoute + '/$project/$version': typeof LibraryProjectVersionIndexRoute + '/$project/$version/docs/framework/$framework': typeof ProjectVersionDocsFrameworkFrameworkRouteWithChildren + '/$project/$version/docs/framework/$framework/$': typeof ProjectVersionDocsFrameworkFrameworkSplatRoute + '/$project/$version/docs/framework/$framework/': typeof ProjectVersionDocsFrameworkFrameworkIndexRoute + '/$project/$version/docs/framework/$framework/examples/$': typeof ProjectVersionDocsFrameworkFrameworkExamplesSplatRoute +} + +export interface FileRoutesByTo { + '/$project': typeof ProjectIndexRoute + '/': typeof LibraryIndexRoute + '/$project/$version/docs': typeof ProjectVersionDocsIndexRoute + '/$project/$version': typeof LibraryProjectVersionIndexRoute + '/$project/$version/docs/framework/$framework/$': typeof ProjectVersionDocsFrameworkFrameworkSplatRoute + '/$project/$version/docs/framework/$framework': typeof ProjectVersionDocsFrameworkFrameworkIndexRoute + '/$project/$version/docs/framework/$framework/examples/$': typeof ProjectVersionDocsFrameworkFrameworkExamplesSplatRoute +} + +export interface FileRoutesById { + __root__: typeof rootRoute + '/_library': typeof LibraryRouteWithChildren + '/_library/$project': typeof LibraryProjectRouteWithChildren + '/$project/': typeof ProjectIndexRoute + '/_library/': typeof LibraryIndexRoute + '/$project/$version/docs/': typeof ProjectVersionDocsIndexRoute + '/_library/$project/$version/': typeof LibraryProjectVersionIndexRoute + '/$project/$version/docs/framework/$framework': typeof ProjectVersionDocsFrameworkFrameworkRouteWithChildren + '/$project/$version/docs/framework/$framework/$': typeof ProjectVersionDocsFrameworkFrameworkSplatRoute + '/$project/$version/docs/framework/$framework/': typeof ProjectVersionDocsFrameworkFrameworkIndexRoute + '/$project/$version/docs/framework/$framework/examples/$': typeof ProjectVersionDocsFrameworkFrameworkExamplesSplatRoute +} + +export interface FileRouteTypes { + fileRoutesByFullPath: FileRoutesByFullPath + fullPaths: + | '' + | '/$project' + | '/' + | '/$project/$version/docs' + | '/$project/$version' + | '/$project/$version/docs/framework/$framework' + | '/$project/$version/docs/framework/$framework/$' + | '/$project/$version/docs/framework/$framework/' + | '/$project/$version/docs/framework/$framework/examples/$' + fileRoutesByTo: FileRoutesByTo + to: + | '/$project' + | '/' + | '/$project/$version/docs' + | '/$project/$version' + | '/$project/$version/docs/framework/$framework/$' + | '/$project/$version/docs/framework/$framework' + | '/$project/$version/docs/framework/$framework/examples/$' + id: + | '__root__' + | '/_library' + | '/_library/$project' + | '/$project/' + | '/_library/' + | '/$project/$version/docs/' + | '/_library/$project/$version/' + | '/$project/$version/docs/framework/$framework' + | '/$project/$version/docs/framework/$framework/$' + | '/$project/$version/docs/framework/$framework/' + | '/$project/$version/docs/framework/$framework/examples/$' + fileRoutesById: FileRoutesById +} + +export interface RootRouteChildren { + LibraryRoute: typeof LibraryRouteWithChildren + ProjectIndexRoute: typeof ProjectIndexRoute + ProjectVersionDocsIndexRoute: typeof ProjectVersionDocsIndexRoute + ProjectVersionDocsFrameworkFrameworkRoute: typeof ProjectVersionDocsFrameworkFrameworkRouteWithChildren +} + +const rootRouteChildren: RootRouteChildren = { + LibraryRoute: LibraryRouteWithChildren, + ProjectIndexRoute: ProjectIndexRoute, + ProjectVersionDocsIndexRoute: ProjectVersionDocsIndexRoute, + ProjectVersionDocsFrameworkFrameworkRoute: + ProjectVersionDocsFrameworkFrameworkRouteWithChildren, +} + +export const routeTree = rootRoute + ._addFileChildren(rootRouteChildren) + ._addFileTypes() + +/* prettier-ignore-end */ + +/* ROUTE_MANIFEST_START +{ + "routes": { + "__root__": { + "filePath": "__root.tsx", + "children": [ + "/_library", + "/$project/", + "/$project/$version/docs/", + "/$project/$version/docs/framework/$framework" + ] + }, + "/_library": { + "filePath": "_library.tsx", + "children": [ + "/_library/$project", + "/_library/" + ] + }, + "/_library/$project": { + "filePath": "_library.$project.tsx", + "parent": "/_library", + "children": [ + "/_library/$project/$version/" + ] + }, + "/$project/": { + "filePath": "$project.index.tsx" + }, + "/_library/": { + "filePath": "_library.index.tsx", + "parent": "/_library" + }, + "/$project/$version/docs/": { + "filePath": "$project.$version.docs.index.tsx" + }, + "/_library/$project/$version/": { + "filePath": "_library.$project.$version.index.tsx", + "parent": "/_library/$project" + }, + "/$project/$version/docs/framework/$framework": { + "filePath": "$project.$version.docs.framework.$framework.tsx", + "children": [ + "/$project/$version/docs/framework/$framework/$", + "/$project/$version/docs/framework/$framework/", + "/$project/$version/docs/framework/$framework/examples/$" + ] + }, + "/$project/$version/docs/framework/$framework/$": { + "filePath": "$project.$version.docs.framework.$framework.$.tsx", + "parent": "/$project/$version/docs/framework/$framework" + }, + "/$project/$version/docs/framework/$framework/": { + "filePath": "$project.$version.docs.framework.$framework.index.tsx", + "parent": "/$project/$version/docs/framework/$framework" + }, + "/$project/$version/docs/framework/$framework/examples/$": { + "filePath": "$project.$version.docs.framework.$framework.examples.$.tsx", + "parent": "/$project/$version/docs/framework/$framework" + } + } +} +ROUTE_MANIFEST_END */ diff --git a/e2e/start/website/app/router.tsx b/e2e/start/website/app/router.tsx new file mode 100644 index 0000000000..822b1463cc --- /dev/null +++ b/e2e/start/website/app/router.tsx @@ -0,0 +1,22 @@ +import { createRouter as createTanStackRouter } from '@tanstack/react-router' +import { routeTree } from './routeTree.gen' +import { DefaultCatchBoundary } from './components/DefaultCatchBoundary' +import { NotFound } from './components/NotFound' + +export function createRouter() { + const router = createTanStackRouter({ + routeTree, + defaultPreload: 'intent', + defaultStaleTime: 5000, + defaultErrorComponent: DefaultCatchBoundary, + defaultNotFoundComponent: () => , + }) + + return router +} + +declare module '@tanstack/react-router' { + interface Register { + router: ReturnType + } +} diff --git a/e2e/start/website/app/routes/$project.$version.docs.framework.$framework.$.tsx b/e2e/start/website/app/routes/$project.$version.docs.framework.$framework.$.tsx new file mode 100644 index 0000000000..b38bebc812 --- /dev/null +++ b/e2e/start/website/app/routes/$project.$version.docs.framework.$framework.$.tsx @@ -0,0 +1,40 @@ +import { ErrorComponent, createFileRoute } from '@tanstack/react-router' +import type { ErrorComponentProps } from '@tanstack/react-router' +import { NotFound } from '~/components/NotFound' +import { getDocument } from '~/server/document' +import { capitalize, seo } from '~/utils/seo' + +export const Route = createFileRoute( + '/$project/$version/docs/framework/$framework/$', +)({ + loader: ({ params: { _splat } }) => getDocument(_splat!), + meta: ({ loaderData, params }) => + seo({ + title: `${loaderData.title} | TanStack ${capitalize(params.project)} ${capitalize(params.framework)}`, + }), + errorComponent: PostErrorComponent, + component: Page, + notFoundComponent: () => { + return Document not found + }, +}) + +function PostErrorComponent({ error }: ErrorComponentProps) { + return +} + +function Page() { + const post = Route.useLoaderData() + + return ( +
+

+ {post.title} +

+
{post.content}
+
+ ) +} diff --git a/e2e/start/website/app/routes/$project.$version.docs.framework.$framework.examples.$.tsx b/e2e/start/website/app/routes/$project.$version.docs.framework.$framework.examples.$.tsx new file mode 100644 index 0000000000..a06b4ec1b3 --- /dev/null +++ b/e2e/start/website/app/routes/$project.$version.docs.framework.$framework.examples.$.tsx @@ -0,0 +1,31 @@ +import { createFileRoute } from '@tanstack/react-router' +import { NotFound } from '~/components/NotFound' +import { capitalize, seo } from '~/utils/seo' + +export const Route = createFileRoute( + '/$project/$version/docs/framework/$framework/examples/$', +)({ + meta: ({ params }) => + seo({ + title: `${capitalize(params._splat || '')} Example | TanStack ${capitalize(params.project)} ${capitalize(params.framework)}`, + }), + component: Page, + notFoundComponent: () => { + return Example not found + }, +}) + +function Page() { + const params = Route.useParams() + + return ( +
+

+ {params._splat} example +

+
+ ) +} diff --git a/e2e/start/website/app/routes/$project.$version.docs.framework.$framework.index.tsx b/e2e/start/website/app/routes/$project.$version.docs.framework.$framework.index.tsx new file mode 100644 index 0000000000..64a30c1ee1 --- /dev/null +++ b/e2e/start/website/app/routes/$project.$version.docs.framework.$framework.index.tsx @@ -0,0 +1,15 @@ +import { createFileRoute, redirect } from '@tanstack/react-router' + +export const Route = createFileRoute( + '/$project/$version/docs/framework/$framework/', +)({ + loader: () => { + throw redirect({ + from: '/$project/$version/docs/framework/$framework/', + to: '/$project/$version/docs/framework/$framework/$', + params: { + _splat: 'overview', + }, + }) + }, +}) diff --git a/e2e/start/website/app/routes/$project.$version.docs.framework.$framework.tsx b/e2e/start/website/app/routes/$project.$version.docs.framework.$framework.tsx new file mode 100644 index 0000000000..8a614e51c8 --- /dev/null +++ b/e2e/start/website/app/routes/$project.$version.docs.framework.$framework.tsx @@ -0,0 +1,123 @@ +import { + Link, + Outlet, + createFileRoute, + useLocation, +} from '@tanstack/react-router' +import { getDocumentHeads } from '~/server/document' +import { getProject } from '~/server/projects' + +export const Route = createFileRoute( + '/$project/$version/docs/framework/$framework', +)({ + loader: async ({ params: { project } }) => { + const library = await getProject(project) + const documents = await getDocumentHeads() + return { + library, + documents, + } + }, + component: Page, +}) + +function Page() { + const project = Route.useLoaderData({ select: (s) => s.library }) + const documents = Route.useLoaderData({ select: (s) => s.documents }) + const pathname = useLocation({ select: (s) => s.pathname }) + + return ( +
+ +
+

+ {pathname} +

+ +
+
+ ) +} diff --git a/e2e/start/website/app/routes/$project.$version.docs.index.tsx b/e2e/start/website/app/routes/$project.$version.docs.index.tsx new file mode 100644 index 0000000000..e379d81908 --- /dev/null +++ b/e2e/start/website/app/routes/$project.$version.docs.index.tsx @@ -0,0 +1,14 @@ +import { createFileRoute, redirect } from '@tanstack/react-router' + +export const Route = createFileRoute('/$project/$version/docs/')({ + loader: () => { + throw redirect({ + from: '/$project/$version/docs', + to: '/$project/$version/docs/framework/$framework/$', + params: { + framework: 'react', + _splat: 'overview', + }, + }) + }, +}) diff --git a/e2e/start/website/app/routes/$project.index.tsx b/e2e/start/website/app/routes/$project.index.tsx new file mode 100644 index 0000000000..9c6b935e83 --- /dev/null +++ b/e2e/start/website/app/routes/$project.index.tsx @@ -0,0 +1,13 @@ +import { createFileRoute, redirect } from '@tanstack/react-router' + +export const Route = createFileRoute('/$project/')({ + loader: ({ params }) => { + throw redirect({ + to: '/$project/$version', + params: { + project: params.project, + version: 'latest', + }, + }) + }, +}) diff --git a/e2e/start/website/app/routes/__root.tsx b/e2e/start/website/app/routes/__root.tsx new file mode 100644 index 0000000000..4f3568e517 --- /dev/null +++ b/e2e/start/website/app/routes/__root.tsx @@ -0,0 +1,83 @@ +import { + Outlet, + ScrollRestoration, + createRootRoute, +} from '@tanstack/react-router' +import { TanStackRouterDevtools } from '@tanstack/router-devtools' +import { Body, Head, Html, Meta, Scripts } from '@tanstack/start' +import * as React from 'react' +import { DefaultCatchBoundary } from '~/components/DefaultCatchBoundary' +import { NotFound } from '~/components/NotFound' +import appCss from '~/styles/app.css?url' +import { seo } from '~/utils/seo' + +export const Route = createRootRoute({ + meta: () => [ + { + charSet: 'utf-8', + }, + { + name: 'viewport', + content: 'width=device-width, initial-scale=1', + }, + ...seo({ + title: 'TanStack Website', + description: `TanStack projects are type-safe!!!`, + }), + ], + links: () => [ + { rel: 'stylesheet', href: appCss }, + { + rel: 'apple-touch-icon', + sizes: '180x180', + href: '/apple-touch-icon.png', + }, + { + rel: 'icon', + type: 'image/png', + sizes: '32x32', + href: '/favicon-32x32.png', + }, + { + rel: 'icon', + type: 'image/png', + sizes: '16x16', + href: '/favicon-16x16.png', + }, + { rel: 'manifest', href: '/site.webmanifest', color: '#fffff' }, + { rel: 'icon', href: '/favicon.ico' }, + ], + errorComponent: (props) => { + return ( + + + + ) + }, + notFoundComponent: () => , + component: RootComponent, +}) + +function RootComponent() { + return ( + + + + ) +} + +function RootDocument({ children }: { children: React.ReactNode }) { + return ( + + + + + + {children} + + + + + + ) +} diff --git a/e2e/start/website/app/routes/_library.$project.$version.index.tsx b/e2e/start/website/app/routes/_library.$project.$version.index.tsx new file mode 100644 index 0000000000..d91b72d2b7 --- /dev/null +++ b/e2e/start/website/app/routes/_library.$project.$version.index.tsx @@ -0,0 +1,23 @@ +import { Link, createFileRoute } from '@tanstack/react-router' + +export const Route = createFileRoute('/_library/$project/$version/')({ + component: Page, +}) + +function Page() { + const params = Route.useParams() + + return ( +
+

+ {params.project} landing page +

+

version: {params.version}

+

+ + Get started with our documentation. + +

+
+ ) +} diff --git a/e2e/start/website/app/routes/_library.$project.tsx b/e2e/start/website/app/routes/_library.$project.tsx new file mode 100644 index 0000000000..817728c173 --- /dev/null +++ b/e2e/start/website/app/routes/_library.$project.tsx @@ -0,0 +1,13 @@ +import { Outlet, createFileRoute } from '@tanstack/react-router' +import { getProject } from '~/server/projects' +import { seo } from '~/utils/seo' + +export const Route = createFileRoute('/_library/$project')({ + loader: ({ params: { project } }) => getProject(project), + meta: ({ loaderData }) => seo({ title: `TanStack ${loaderData.name}` }), + component: () => ( +
+ +
+ ), +}) diff --git a/e2e/start/website/app/routes/_library.index.tsx b/e2e/start/website/app/routes/_library.index.tsx new file mode 100644 index 0000000000..f08b6c633a --- /dev/null +++ b/e2e/start/website/app/routes/_library.index.tsx @@ -0,0 +1,13 @@ +import { createFileRoute } from '@tanstack/react-router' + +export const Route = createFileRoute('/_library/')({ + component: Home, +}) + +function Home() { + return ( +
+

Website Landing Page

+
+ ) +} diff --git a/e2e/start/website/app/routes/_library.tsx b/e2e/start/website/app/routes/_library.tsx new file mode 100644 index 0000000000..e120515350 --- /dev/null +++ b/e2e/start/website/app/routes/_library.tsx @@ -0,0 +1,62 @@ +import { + Link, + Outlet, + createFileRoute, + useLocation, +} from '@tanstack/react-router' +import { getProjects } from '~/server/projects' + +export const Route = createFileRoute('/_library')({ + loader: async () => { + const projects = await getProjects() + return { + libraries: projects, + } + }, + component: Layout, +}) + +function Layout() { + const { libraries } = Route.useLoaderData() + const pathname = useLocation({ select: (s) => s.pathname }) + return ( +
+ +
+

+ {pathname} +

+ +
+
+ ) +} diff --git a/e2e/start/website/app/server/document.tsx b/e2e/start/website/app/server/document.tsx new file mode 100644 index 0000000000..759c63920e --- /dev/null +++ b/e2e/start/website/app/server/document.tsx @@ -0,0 +1,51 @@ +import { notFound } from '@tanstack/react-router' +import { createServerFn } from '@tanstack/start' + +const documents: Array<{ id: string; title: string; content: string }> = [ + { + id: 'overview', + title: 'Overview', + content: 'This is the content of the overview document', + }, + { + id: 'getting-started', + title: 'Getting Started', + content: 'To get started, you need to do the following...', + }, + { + id: 'installation', + title: 'Installation', + content: 'To install this package, run the following command...', + }, + { + id: 'ref/useQueryFunction', + title: 'useQuery Reference', + content: 'The useQuery function is used to...', + }, + { + id: 'ref/useMutationFunction', + title: 'useMutation Reference', + content: 'The useMutation function is used to...', + }, +] + +export const getDocumentHeads = createServerFn('GET', async () => { + await new Promise((resolve) => setTimeout(resolve, 200)) + + return documents.map(({ id, title }) => ({ + id, + title, + })) +}) + +export const getDocument = createServerFn('GET', async (id: string) => { + await new Promise((resolve) => setTimeout(resolve, 200)) + + const document = documents.find((doc) => doc.id === id) + + if (!document) { + throw notFound() + } + + return document +}) diff --git a/e2e/start/website/app/server/projects.tsx b/e2e/start/website/app/server/projects.tsx new file mode 100644 index 0000000000..b76bf05feb --- /dev/null +++ b/e2e/start/website/app/server/projects.tsx @@ -0,0 +1,29 @@ +import { createServerFn } from '@tanstack/start' +import { notFound } from '@tanstack/react-router' +import { capitalize } from '~/utils/seo' + +const projects = ['router', 'table', 'query', 'form', 'ranger'] + +export const getProjects = createServerFn('GET', async () => { + await new Promise((resolve) => setTimeout(resolve, 200)) + + return projects +}) + +export const getProject = createServerFn('GET', async (project: string) => { + await new Promise((resolve) => setTimeout(resolve, 200)) + + const selectedProject = projects.find((p) => p === project.toLowerCase()) + + if (!selectedProject) { + throw notFound() + } + + return { + id: selectedProject, + name: capitalize(selectedProject), + versions: ['latest', 'v2', 'v1'], + frameworks: ['react', 'vue', 'solidjs', 'svelte'], + examples: ['basic', 'kitchen-sink'], + } +}) diff --git a/e2e/start/website/app/ssr.tsx b/e2e/start/website/app/ssr.tsx new file mode 100644 index 0000000000..f2d33f9030 --- /dev/null +++ b/e2e/start/website/app/ssr.tsx @@ -0,0 +1,13 @@ +/// +import { + createStartHandler, + defaultStreamHandler, +} from '@tanstack/start/server' +import { getRouterManifest } from '@tanstack/start/router-manifest' + +import { createRouter } from './router' + +export default createStartHandler({ + createRouter, + getRouterManifest, +})(defaultStreamHandler) diff --git a/e2e/start/website/app/styles/app.css b/e2e/start/website/app/styles/app.css new file mode 100644 index 0000000000..d6426ccb72 --- /dev/null +++ b/e2e/start/website/app/styles/app.css @@ -0,0 +1,14 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +@layer base { + html, + body { + @apply text-gray-900 bg-gray-50 dark:bg-gray-950 dark:text-gray-200; + } + + .using-mouse * { + outline: none !important; + } +} diff --git a/e2e/start/website/app/utils/seo.ts b/e2e/start/website/app/utils/seo.ts new file mode 100644 index 0000000000..82cf2aec07 --- /dev/null +++ b/e2e/start/website/app/utils/seo.ts @@ -0,0 +1,36 @@ +export const seo = ({ + title, + description, + keywords, + image, +}: { + title: string + description?: string + image?: string + keywords?: string +}) => { + const tags = [ + { title }, + { name: 'description', content: description }, + { name: 'keywords', content: keywords }, + { name: 'twitter:title', content: title }, + { name: 'twitter:description', content: description }, + { name: 'twitter:creator', content: '@tannerlinsley' }, + { name: 'twitter:site', content: '@tannerlinsley' }, + { name: 'og:type', content: 'website' }, + { name: 'og:title', content: title }, + { name: 'og:description', content: description }, + ...(image + ? [ + { name: 'twitter:image', content: image }, + { name: 'twitter:card', content: 'summary_large_image' }, + { name: 'og:image', content: image }, + ] + : []), + ] + + return tags +} + +export const capitalize = (str: string) => + str.charAt(0).toUpperCase() + str.slice(1) diff --git a/e2e/start/website/package.json b/e2e/start/website/package.json new file mode 100644 index 0000000000..f88b0c60c4 --- /dev/null +++ b/e2e/start/website/package.json @@ -0,0 +1,35 @@ +{ + "name": "tanstack-start-e2e-website", + "private": true, + "sideEffects": false, + "type": "module", + "scripts": { + "dev": "vinxi dev --port 3010", + "build": "vinxi build", + "start": "vinxi start", + "test:e2e": "playwright test --project=chromium" + }, + "dependencies": { + "@tanstack/react-router": "workspace:^", + "@tanstack/router-devtools": "workspace:^", + "@tanstack/start": "workspace:^", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "redaxios": "^0.5.1", + "tailwind-merge": "^2.5.4", + "vinxi": "0.4.3", + "zod": "^3.23.8" + }, + "devDependencies": { + "@playwright/test": "^1.48.2", + "@types/node": "^22.5.4", + "@types/react": "^18.2.65", + "@types/react-dom": "^18.2.21", + "@vitejs/plugin-react": "^4.3.3", + "autoprefixer": "^10.4.20", + "postcss": "^8.4.47", + "tailwindcss": "^3.4.14", + "typescript": "^5.6.2", + "vite-tsconfig-paths": "^5.0.1" + } +} diff --git a/e2e/start/website/playwright.config.ts b/e2e/start/website/playwright.config.ts new file mode 100644 index 0000000000..5fbb3e3429 --- /dev/null +++ b/e2e/start/website/playwright.config.ts @@ -0,0 +1,30 @@ +import { defineConfig, devices } from '@playwright/test' + +/** + * See https://playwright.dev/docs/test-configuration. + */ +export default defineConfig({ + testDir: './tests', + + reporter: [['line']], + + use: { + /* Base URL to use in actions like `await page.goto('/')`. */ + baseURL: 'http://localhost:3010/', + }, + + webServer: { + // TODO: build && start seems broken, use that if it's working + command: 'pnpm run dev', + url: 'http://localhost:3010', + reuseExistingServer: !process.env.CI, + stdout: 'pipe', + }, + + projects: [ + { + name: 'chromium', + use: { ...devices['Desktop Chrome'] }, + }, + ], +}) diff --git a/e2e/start/website/postcss.config.cjs b/e2e/start/website/postcss.config.cjs new file mode 100644 index 0000000000..8e638a6bcd --- /dev/null +++ b/e2e/start/website/postcss.config.cjs @@ -0,0 +1,7 @@ +module.exports = { + plugins: [ + require('tailwindcss/nesting'), + require('tailwindcss'), + require('autoprefixer'), + ], +} diff --git a/e2e/start/website/public/android-chrome-192x192.png b/e2e/start/website/public/android-chrome-192x192.png new file mode 100644 index 0000000000..09c8324f8c Binary files /dev/null and b/e2e/start/website/public/android-chrome-192x192.png differ diff --git a/e2e/start/website/public/android-chrome-512x512.png b/e2e/start/website/public/android-chrome-512x512.png new file mode 100644 index 0000000000..11d626ea3d Binary files /dev/null and b/e2e/start/website/public/android-chrome-512x512.png differ diff --git a/e2e/start/website/public/apple-touch-icon.png b/e2e/start/website/public/apple-touch-icon.png new file mode 100644 index 0000000000..5a9423cc02 Binary files /dev/null and b/e2e/start/website/public/apple-touch-icon.png differ diff --git a/e2e/start/website/public/favicon-16x16.png b/e2e/start/website/public/favicon-16x16.png new file mode 100644 index 0000000000..e3389b0044 Binary files /dev/null and b/e2e/start/website/public/favicon-16x16.png differ diff --git a/e2e/start/website/public/favicon-32x32.png b/e2e/start/website/public/favicon-32x32.png new file mode 100644 index 0000000000..900c77d444 Binary files /dev/null and b/e2e/start/website/public/favicon-32x32.png differ diff --git a/e2e/start/website/public/favicon.ico b/e2e/start/website/public/favicon.ico new file mode 100644 index 0000000000..1a1751676f Binary files /dev/null and b/e2e/start/website/public/favicon.ico differ diff --git a/e2e/start/website/public/favicon.png b/e2e/start/website/public/favicon.png new file mode 100644 index 0000000000..1e77bc0609 Binary files /dev/null and b/e2e/start/website/public/favicon.png differ diff --git a/e2e/start/website/public/site.webmanifest b/e2e/start/website/public/site.webmanifest new file mode 100644 index 0000000000..fa99de77db --- /dev/null +++ b/e2e/start/website/public/site.webmanifest @@ -0,0 +1,19 @@ +{ + "name": "", + "short_name": "", + "icons": [ + { + "src": "/android-chrome-192x192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "/android-chrome-512x512.png", + "sizes": "512x512", + "type": "image/png" + } + ], + "theme_color": "#ffffff", + "background_color": "#ffffff", + "display": "standalone" +} diff --git a/e2e/start/website/tailwind.config.cjs b/e2e/start/website/tailwind.config.cjs new file mode 100644 index 0000000000..75fe25dbf7 --- /dev/null +++ b/e2e/start/website/tailwind.config.cjs @@ -0,0 +1,4 @@ +/** @type {import('tailwindcss').Config} */ +module.exports = { + content: ['./app/**/*.{js,ts,jsx,tsx}'], +} diff --git a/e2e/start/website/tests/app.spec.ts b/e2e/start/website/tests/app.spec.ts new file mode 100644 index 0000000000..f115180956 --- /dev/null +++ b/e2e/start/website/tests/app.spec.ts @@ -0,0 +1,19 @@ +import { expect, test } from '@playwright/test' + +const routeTestId = 'selected-route-label' + +test('resolves to the latest version on load of a project like "/router"', async ({ + page, +}) => { + await page.goto('/router') + + await expect(page.getByTestId(routeTestId)).toContainText('/router/latest') +}) + +test('resolves to the overview docs page', async ({ page }) => { + await page.goto('/router/latest/docs') + + await expect(page.getByTestId(routeTestId)).toContainText( + '/router/latest/docs/framework/react/overview', + ) +}) diff --git a/e2e/start/website/tsconfig.json b/e2e/start/website/tsconfig.json new file mode 100644 index 0000000000..d1b5b77660 --- /dev/null +++ b/e2e/start/website/tsconfig.json @@ -0,0 +1,22 @@ +{ + "include": ["**/*.ts", "**/*.tsx"], + "compilerOptions": { + "strict": true, + "esModuleInterop": true, + "jsx": "react-jsx", + "module": "ESNext", + "moduleResolution": "Bundler", + "lib": ["DOM", "DOM.Iterable", "ES2022"], + "isolatedModules": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "target": "ES2022", + "allowJs": true, + "forceConsistentCasingInFileNames": true, + "baseUrl": ".", + "paths": { + "~/*": ["./app/*"] + }, + "noEmit": true + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d9473bc961..5a6ca79d42 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -777,6 +777,67 @@ importers: specifier: ^5.0.1 version: 5.0.1(typescript@5.6.3)(vite@5.4.10(@types/node@22.7.4)(terser@5.31.1)) + e2e/start/website: + dependencies: + '@tanstack/react-router': + specifier: workspace:* + version: link:../../../packages/react-router + '@tanstack/router-devtools': + specifier: workspace:* + version: link:../../../packages/router-devtools + '@tanstack/start': + specifier: workspace:* + version: link:../../../packages/start + react: + specifier: ^18.3.1 + version: 18.3.1 + react-dom: + specifier: ^18.3.1 + version: 18.3.1(react@18.3.1) + redaxios: + specifier: ^0.5.1 + version: 0.5.1 + tailwind-merge: + specifier: ^2.5.4 + version: 2.5.4 + vinxi: + specifier: 0.4.3 + version: 0.4.3(@types/node@22.7.4)(ioredis@5.4.1)(terser@5.31.1)(webpack-sources@3.2.3) + zod: + specifier: ^3.23.8 + version: 3.23.8 + devDependencies: + '@playwright/test': + specifier: ^1.48.2 + version: 1.48.2 + '@types/node': + specifier: ^22.5.4 + version: 22.7.4 + '@types/react': + specifier: ^18.2.65 + version: 18.3.11 + '@types/react-dom': + specifier: ^18.2.21 + version: 18.3.0 + '@vitejs/plugin-react': + specifier: ^4.3.3 + version: 4.3.3(vite@5.4.10(@types/node@22.7.4)(terser@5.31.1)) + autoprefixer: + specifier: ^10.4.20 + version: 10.4.20(postcss@8.4.47) + postcss: + specifier: ^8.4.47 + version: 8.4.47 + tailwindcss: + specifier: ^3.4.14 + version: 3.4.14 + typescript: + specifier: ^5.6.2 + version: 5.6.3 + vite-tsconfig-paths: + specifier: ^5.0.1 + version: 5.0.1(typescript@5.6.3)(vite@5.4.10(@types/node@22.7.4)(terser@5.31.1)) + examples/react/authenticated-routes: dependencies: '@tanstack/react-router':