From e27a8493b1dd88fb733a2214492d2576af5eeb54 Mon Sep 17 00:00:00 2001 From: Birk Skyum Date: Tue, 30 Sep 2025 17:55:05 +0200 Subject: [PATCH 1/3] solid-router-ssr-query --- .../basic-solid-query/package.json | 37 +++ .../playwright-report/index.html | 77 ++++++ .../basic-solid-query/playwright.config.ts | 39 +++ .../basic-solid-query/postcss.config.mjs | 6 + .../src/components/DefaultCatchBoundary.tsx | 8 + .../src/components/NotFound.tsx | 24 ++ .../basic-solid-query/src/routeTree.gen.ts | 231 ++++++++++++++++++ .../basic-solid-query/src/router.tsx | 30 +++ .../basic-solid-query/src/routes/__root.tsx | 125 ++++++++++ .../basic-solid-query/src/routes/deferred.tsx | 54 ++++ .../basic-solid-query/src/routes/index.tsx | 13 + .../src/routes/posts.$postId.tsx | 27 ++ .../src/routes/posts.index.tsx | 9 + .../basic-solid-query/src/routes/posts.tsx | 48 ++++ .../src/routes/users.$userId.tsx | 34 +++ .../src/routes/users.index.tsx | 9 + .../basic-solid-query/src/routes/users.tsx | 46 ++++ .../basic-solid-query/src/styles/app.css | 8 + .../basic-solid-query/src/utils/posts.tsx | 33 +++ .../basic-solid-query/src/utils/seo.ts | 30 +++ .../basic-solid-query/src/utils/users.tsx | 37 +++ .../basic-solid-query/tailwind.config.mjs | 8 + .../basic-solid-query/tests/app.spec.ts | 36 +++ .../tests/setup/global.setup.ts | 1 + .../tests/setup/global.teardown.ts | 1 + .../basic-solid-query/tsconfig.json | 24 ++ .../basic-solid-query/vite.config.ts | 14 ++ .../query-integration/package.json | 36 +++ .../query-integration/playwright.config.ts | 36 +++ .../query-integration/postcss.config.mjs | 6 + .../query-integration/src/queryOptions.ts | 16 ++ .../query-integration/src/routeTree.gen.ts | 104 ++++++++ .../query-integration/src/router.tsx | 26 ++ .../query-integration/src/routes/__root.tsx | 84 +++++++ .../query-integration/src/routes/index.tsx | 13 + .../src/routes/loader-fetchQuery/$type.tsx | 45 ++++ .../query-integration/src/routes/useQuery.tsx | 23 ++ .../query-integration/src/styles/app.css | 8 + .../query-integration/tailwind.config.mjs | 8 + .../query-integration/tests/app.spec.ts | 34 +++ .../query-integration/tsconfig.json | 24 ++ .../query-integration/vite.config.ts | 14 ++ package.json | 1 + packages/solid-router-ssr-query/README.md | 38 +++ .../solid-router-ssr-query/eslint.config.js | 12 + packages/solid-router-ssr-query/package.json | 81 ++++++ packages/solid-router-ssr-query/src/index.tsx | 30 +++ packages/solid-router-ssr-query/tsconfig.json | 8 + .../solid-router-ssr-query/vite.config.ts | 24 ++ pnpm-lock.yaml | 148 +++++++++++ 50 files changed, 1828 insertions(+) create mode 100644 e2e/solid-start/basic-solid-query/package.json create mode 100644 e2e/solid-start/basic-solid-query/playwright-report/index.html create mode 100644 e2e/solid-start/basic-solid-query/playwright.config.ts create mode 100644 e2e/solid-start/basic-solid-query/postcss.config.mjs create mode 100644 e2e/solid-start/basic-solid-query/src/components/DefaultCatchBoundary.tsx create mode 100644 e2e/solid-start/basic-solid-query/src/components/NotFound.tsx create mode 100644 e2e/solid-start/basic-solid-query/src/routeTree.gen.ts create mode 100644 e2e/solid-start/basic-solid-query/src/router.tsx create mode 100644 e2e/solid-start/basic-solid-query/src/routes/__root.tsx create mode 100644 e2e/solid-start/basic-solid-query/src/routes/deferred.tsx create mode 100644 e2e/solid-start/basic-solid-query/src/routes/index.tsx create mode 100644 e2e/solid-start/basic-solid-query/src/routes/posts.$postId.tsx create mode 100644 e2e/solid-start/basic-solid-query/src/routes/posts.index.tsx create mode 100644 e2e/solid-start/basic-solid-query/src/routes/posts.tsx create mode 100644 e2e/solid-start/basic-solid-query/src/routes/users.$userId.tsx create mode 100644 e2e/solid-start/basic-solid-query/src/routes/users.index.tsx create mode 100644 e2e/solid-start/basic-solid-query/src/routes/users.tsx create mode 100644 e2e/solid-start/basic-solid-query/src/styles/app.css create mode 100644 e2e/solid-start/basic-solid-query/src/utils/posts.tsx create mode 100644 e2e/solid-start/basic-solid-query/src/utils/seo.ts create mode 100644 e2e/solid-start/basic-solid-query/src/utils/users.tsx create mode 100644 e2e/solid-start/basic-solid-query/tailwind.config.mjs create mode 100644 e2e/solid-start/basic-solid-query/tests/app.spec.ts create mode 100644 e2e/solid-start/basic-solid-query/tests/setup/global.setup.ts create mode 100644 e2e/solid-start/basic-solid-query/tests/setup/global.teardown.ts create mode 100644 e2e/solid-start/basic-solid-query/tsconfig.json create mode 100644 e2e/solid-start/basic-solid-query/vite.config.ts create mode 100644 e2e/solid-start/query-integration/package.json create mode 100644 e2e/solid-start/query-integration/playwright.config.ts create mode 100644 e2e/solid-start/query-integration/postcss.config.mjs create mode 100644 e2e/solid-start/query-integration/src/queryOptions.ts create mode 100644 e2e/solid-start/query-integration/src/routeTree.gen.ts create mode 100644 e2e/solid-start/query-integration/src/router.tsx create mode 100644 e2e/solid-start/query-integration/src/routes/__root.tsx create mode 100644 e2e/solid-start/query-integration/src/routes/index.tsx create mode 100644 e2e/solid-start/query-integration/src/routes/loader-fetchQuery/$type.tsx create mode 100644 e2e/solid-start/query-integration/src/routes/useQuery.tsx create mode 100644 e2e/solid-start/query-integration/src/styles/app.css create mode 100644 e2e/solid-start/query-integration/tailwind.config.mjs create mode 100644 e2e/solid-start/query-integration/tests/app.spec.ts create mode 100644 e2e/solid-start/query-integration/tsconfig.json create mode 100644 e2e/solid-start/query-integration/vite.config.ts create mode 100644 packages/solid-router-ssr-query/README.md create mode 100644 packages/solid-router-ssr-query/eslint.config.js create mode 100644 packages/solid-router-ssr-query/package.json create mode 100644 packages/solid-router-ssr-query/src/index.tsx create mode 100644 packages/solid-router-ssr-query/tsconfig.json create mode 100644 packages/solid-router-ssr-query/vite.config.ts diff --git a/e2e/solid-start/basic-solid-query/package.json b/e2e/solid-start/basic-solid-query/package.json new file mode 100644 index 0000000000..4baacabf7c --- /dev/null +++ b/e2e/solid-start/basic-solid-query/package.json @@ -0,0 +1,37 @@ +{ + "name": "tanstack-solid-start-e2e-basic-solid-query", + "private": true, + "sideEffects": false, + "type": "module", + "scripts": { + "dev": "vite dev --port 3000", + "dev:e2e": "vite dev", + "build": "vite build && tsc --noEmit", + "start": "pnpx srvx --prod -s ../client dist/server/server.js", + "test:e2e": "rm -rf port*.txt; playwright test --project=chromium" + }, + "dependencies": { + "@tanstack/solid-query": "^5.66.0", + "@tanstack/solid-query-devtools": "^5.66.0", + "@tanstack/solid-router": "workspace:^", + "@tanstack/solid-router-devtools": "workspace:^", + "@tanstack/solid-router-ssr-query": "workspace:^", + "@tanstack/solid-start": "workspace:^", + "solid-js": "^1.9.5", + "redaxios": "^0.5.1", + "tailwind-merge": "^2.6.0", + "vite": "^7.1.7" + }, + "devDependencies": { + "@playwright/test": "^1.50.1", + "@tanstack/router-e2e-utils": "workspace:^", + "@types/node": "^22.10.2", + "autoprefixer": "^10.4.20", + "postcss": "^8.5.1", + "srvx": "^0.8.6", + "tailwindcss": "^3.4.17", + "typescript": "^5.7.2", + "vite-plugin-solid": "^2.11.8", + "vite-tsconfig-paths": "^5.1.4" + } +} \ No newline at end of file diff --git a/e2e/solid-start/basic-solid-query/playwright-report/index.html b/e2e/solid-start/basic-solid-query/playwright-report/index.html new file mode 100644 index 0000000000..2d3e74e45d --- /dev/null +++ b/e2e/solid-start/basic-solid-query/playwright-report/index.html @@ -0,0 +1,77 @@ + + + + + + + + + Playwright Test Report + + + + +
+ + + \ No newline at end of file diff --git a/e2e/solid-start/basic-solid-query/playwright.config.ts b/e2e/solid-start/basic-solid-query/playwright.config.ts new file mode 100644 index 0000000000..7e0487c881 --- /dev/null +++ b/e2e/solid-start/basic-solid-query/playwright.config.ts @@ -0,0 +1,39 @@ +import { defineConfig, devices } from '@playwright/test' +import { + getDummyServerPort, + getTestServerPort, +} from '@tanstack/router-e2e-utils' +import packageJson from './package.json' with { type: 'json' } + +const PORT = await getTestServerPort(packageJson.name) +const EXTERNAL_PORT = await getDummyServerPort(packageJson.name) + +const baseURL = `http://localhost:${PORT}` + +export default defineConfig({ + testDir: './tests', + workers: 1, + + reporter: [['line']], + + globalSetup: './tests/setup/global.setup.ts', + globalTeardown: './tests/setup/global.teardown.ts', + + use: { + baseURL, + }, + + webServer: { + command: `VITE_NODE_ENV="test" VITE_EXTERNAL_PORT=${EXTERNAL_PORT} VITE_SERVER_PORT=${PORT} pnpm build && VITE_NODE_ENV="test" VITE_EXTERNAL_PORT=${EXTERNAL_PORT} PORT=${PORT} VITE_SERVER_PORT=${PORT} pnpm start`, + url: baseURL, + reuseExistingServer: !process.env.CI, + stdout: 'pipe', + }, + + projects: [ + { + name: 'chromium', + use: { ...devices['Desktop Chrome'] }, + }, + ], +}) \ No newline at end of file diff --git a/e2e/solid-start/basic-solid-query/postcss.config.mjs b/e2e/solid-start/basic-solid-query/postcss.config.mjs new file mode 100644 index 0000000000..e99ebc2c0e --- /dev/null +++ b/e2e/solid-start/basic-solid-query/postcss.config.mjs @@ -0,0 +1,6 @@ +export default { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +} \ No newline at end of file diff --git a/e2e/solid-start/basic-solid-query/src/components/DefaultCatchBoundary.tsx b/e2e/solid-start/basic-solid-query/src/components/DefaultCatchBoundary.tsx new file mode 100644 index 0000000000..92058c37f8 --- /dev/null +++ b/e2e/solid-start/basic-solid-query/src/components/DefaultCatchBoundary.tsx @@ -0,0 +1,8 @@ +import { + ErrorComponent, + type ErrorComponentProps, +} from '@tanstack/solid-router' + +export function DefaultCatchBoundary(props: ErrorComponentProps) { + return +} \ No newline at end of file diff --git a/e2e/solid-start/basic-solid-query/src/components/NotFound.tsx b/e2e/solid-start/basic-solid-query/src/components/NotFound.tsx new file mode 100644 index 0000000000..4040aa7fcd --- /dev/null +++ b/e2e/solid-start/basic-solid-query/src/components/NotFound.tsx @@ -0,0 +1,24 @@ +import { Link } from '@tanstack/solid-router' +import type { JSX } from 'solid-js' + +export function NotFound(props?: { children?: JSX.Element }) { + return ( +
+
{props?.children || 'The page you are looking for does not exist.'}
+

+ + + Start Over + +

+
+ ) +} \ No newline at end of file diff --git a/e2e/solid-start/basic-solid-query/src/routeTree.gen.ts b/e2e/solid-start/basic-solid-query/src/routeTree.gen.ts new file mode 100644 index 0000000000..5f2844e46d --- /dev/null +++ b/e2e/solid-start/basic-solid-query/src/routeTree.gen.ts @@ -0,0 +1,231 @@ +/* eslint-disable */ + +// @ts-nocheck + +// noinspection JSUnusedGlobalSymbols + +// This file was automatically generated by TanStack Router. +// You should NOT make any changes in this file as it will be overwritten. +// 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 UsersRouteImport } from './routes/users' +import { Route as PostsRouteImport } from './routes/posts' +import { Route as DeferredRouteImport } from './routes/deferred' +import { Route as IndexRouteImport } from './routes/index' +import { Route as UsersIndexRouteImport } from './routes/users.index' +import { Route as PostsIndexRouteImport } from './routes/posts.index' +import { Route as UsersUserIdRouteImport } from './routes/users.$userId' +import { Route as PostsPostIdRouteImport } from './routes/posts.$postId' + +const UsersRoute = UsersRouteImport.update({ + id: '/users', + path: '/users', + getParentRoute: () => rootRouteImport, +} as any) +const PostsRoute = PostsRouteImport.update({ + id: '/posts', + path: '/posts', + getParentRoute: () => rootRouteImport, +} as any) +const DeferredRoute = DeferredRouteImport.update({ + id: '/deferred', + path: '/deferred', + getParentRoute: () => rootRouteImport, +} as any) +const IndexRoute = IndexRouteImport.update({ + id: '/', + path: '/', + getParentRoute: () => rootRouteImport, +} as any) +const UsersIndexRoute = UsersIndexRouteImport.update({ + id: '/', + path: '/', + getParentRoute: () => UsersRoute, +} as any) +const PostsIndexRoute = PostsIndexRouteImport.update({ + id: '/', + path: '/', + getParentRoute: () => PostsRoute, +} as any) +const UsersUserIdRoute = UsersUserIdRouteImport.update({ + id: '/$userId', + path: '/$userId', + getParentRoute: () => UsersRoute, +} as any) +const PostsPostIdRoute = PostsPostIdRouteImport.update({ + id: '/$postId', + path: '/$postId', + getParentRoute: () => PostsRoute, +} as any) + +export interface FileRoutesByFullPath { + '/': typeof IndexRoute + '/deferred': typeof DeferredRoute + '/posts': typeof PostsRouteWithChildren + '/users': typeof UsersRouteWithChildren + '/posts/$postId': typeof PostsPostIdRoute + '/users/$userId': typeof UsersUserIdRoute + '/posts/': typeof PostsIndexRoute + '/users/': typeof UsersIndexRoute +} +export interface FileRoutesByTo { + '/': typeof IndexRoute + '/deferred': typeof DeferredRoute + '/posts/$postId': typeof PostsPostIdRoute + '/users/$userId': typeof UsersUserIdRoute + '/posts': typeof PostsIndexRoute + '/users': typeof UsersIndexRoute +} +export interface FileRoutesById { + __root__: typeof rootRouteImport + '/': typeof IndexRoute + '/deferred': typeof DeferredRoute + '/posts': typeof PostsRouteWithChildren + '/users': typeof UsersRouteWithChildren + '/posts/$postId': typeof PostsPostIdRoute + '/users/$userId': typeof UsersUserIdRoute + '/posts/': typeof PostsIndexRoute + '/users/': typeof UsersIndexRoute +} +export interface FileRouteTypes { + fileRoutesByFullPath: FileRoutesByFullPath + fullPaths: + | '/' + | '/deferred' + | '/posts' + | '/users' + | '/posts/$postId' + | '/users/$userId' + | '/posts/' + | '/users/' + fileRoutesByTo: FileRoutesByTo + to: + | '/' + | '/deferred' + | '/posts/$postId' + | '/users/$userId' + | '/posts' + | '/users' + id: + | '__root__' + | '/' + | '/deferred' + | '/posts' + | '/users' + | '/posts/$postId' + | '/users/$userId' + | '/posts/' + | '/users/' + fileRoutesById: FileRoutesById +} +export interface RootRouteChildren { + IndexRoute: typeof IndexRoute + DeferredRoute: typeof DeferredRoute + PostsRoute: typeof PostsRouteWithChildren + UsersRoute: typeof UsersRouteWithChildren +} + +declare module '@tanstack/solid-router' { + interface FileRoutesByPath { + '/users': { + id: '/users' + path: '/users' + fullPath: '/users' + preLoaderRoute: typeof UsersRouteImport + parentRoute: typeof rootRouteImport + } + '/posts': { + id: '/posts' + path: '/posts' + fullPath: '/posts' + preLoaderRoute: typeof PostsRouteImport + parentRoute: typeof rootRouteImport + } + '/deferred': { + id: '/deferred' + path: '/deferred' + fullPath: '/deferred' + preLoaderRoute: typeof DeferredRouteImport + parentRoute: typeof rootRouteImport + } + '/': { + id: '/' + path: '/' + fullPath: '/' + preLoaderRoute: typeof IndexRouteImport + parentRoute: typeof rootRouteImport + } + '/users/': { + id: '/users/' + path: '/' + fullPath: '/users/' + preLoaderRoute: typeof UsersIndexRouteImport + parentRoute: typeof UsersRoute + } + '/posts/': { + id: '/posts/' + path: '/' + fullPath: '/posts/' + preLoaderRoute: typeof PostsIndexRouteImport + parentRoute: typeof PostsRoute + } + '/users/$userId': { + id: '/users/$userId' + path: '/$userId' + fullPath: '/users/$userId' + preLoaderRoute: typeof UsersUserIdRouteImport + parentRoute: typeof UsersRoute + } + '/posts/$postId': { + id: '/posts/$postId' + path: '/$postId' + fullPath: '/posts/$postId' + preLoaderRoute: typeof PostsPostIdRouteImport + parentRoute: typeof PostsRoute + } + } +} + +interface PostsRouteChildren { + PostsPostIdRoute: typeof PostsPostIdRoute + PostsIndexRoute: typeof PostsIndexRoute +} + +const PostsRouteChildren: PostsRouteChildren = { + PostsPostIdRoute: PostsPostIdRoute, + PostsIndexRoute: PostsIndexRoute, +} + +const PostsRouteWithChildren = PostsRoute._addFileChildren(PostsRouteChildren) + +interface UsersRouteChildren { + UsersUserIdRoute: typeof UsersUserIdRoute + UsersIndexRoute: typeof UsersIndexRoute +} + +const UsersRouteChildren: UsersRouteChildren = { + UsersUserIdRoute: UsersUserIdRoute, + UsersIndexRoute: UsersIndexRoute, +} + +const UsersRouteWithChildren = UsersRoute._addFileChildren(UsersRouteChildren) + +const rootRouteChildren: RootRouteChildren = { + IndexRoute: IndexRoute, + DeferredRoute: DeferredRoute, + PostsRoute: PostsRouteWithChildren, + UsersRoute: UsersRouteWithChildren, +} +export const routeTree = rootRouteImport + ._addFileChildren(rootRouteChildren) + ._addFileTypes() + +import type { getRouter } from './router.tsx' +import type { createStart } from '@tanstack/solid-start' +declare module '@tanstack/solid-start' { + interface Register { + ssr: true + router: Awaited> + } +} diff --git a/e2e/solid-start/basic-solid-query/src/router.tsx b/e2e/solid-start/basic-solid-query/src/router.tsx new file mode 100644 index 0000000000..f93fb9061e --- /dev/null +++ b/e2e/solid-start/basic-solid-query/src/router.tsx @@ -0,0 +1,30 @@ +import { QueryClient } from '@tanstack/solid-query' +import { createRouter } from '@tanstack/solid-router' +import { setupRouterSsrQueryIntegration } from '@tanstack/solid-router-ssr-query' +import { routeTree } from './routeTree.gen' +import { DefaultCatchBoundary } from './components/DefaultCatchBoundary' +import { NotFound } from './components/NotFound' + +export function getRouter() { + const queryClient = new QueryClient({ + defaultOptions: { + queries: { + // Enable only on client to avoid hydration mismatches + experimental_prefetchInRender: typeof window !== 'undefined', + }, + }, + }) + const router = createRouter({ + routeTree, + context: { queryClient }, + scrollRestoration: true, + defaultPreload: 'intent', + defaultErrorComponent: DefaultCatchBoundary, + defaultNotFoundComponent: () => , + }) + setupRouterSsrQueryIntegration({ + router, + queryClient, + }) + return router +} \ No newline at end of file diff --git a/e2e/solid-start/basic-solid-query/src/routes/__root.tsx b/e2e/solid-start/basic-solid-query/src/routes/__root.tsx new file mode 100644 index 0000000000..4af6a08ab9 --- /dev/null +++ b/e2e/solid-start/basic-solid-query/src/routes/__root.tsx @@ -0,0 +1,125 @@ +/// +import { + HeadContent, + Link, + Outlet, + Scripts, + createRootRouteWithContext, +} from '@tanstack/solid-router' +import { TanStackRouterDevtoolsInProd } from '@tanstack/solid-router-devtools' +import type { QueryClient } from '@tanstack/solid-query' +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 = createRootRouteWithContext<{ + queryClient: QueryClient +}>()({ + head: () => ({ + meta: [ + { + charset: 'utf-8', + }, + { + name: 'viewport', + content: 'width=device-width, initial-scale=1', + }, + ...seo({ + title: + 'TanStack Start | Type-Safe, Client-First, Full-Stack Solid Framework', + description: `TanStack Start is a type-safe, client-first, full-stack Solid framework. `, + }), + ], + 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(props: { children?: any }) { + return ( + + + + + +
+ + Home + {' '} + + Posts + {' '} + + Users + {' '} + + Deferred + +
+
+ {props.children} + + + + + ) +} \ No newline at end of file diff --git a/e2e/solid-start/basic-solid-query/src/routes/deferred.tsx b/e2e/solid-start/basic-solid-query/src/routes/deferred.tsx new file mode 100644 index 0000000000..2fa71ccbb5 --- /dev/null +++ b/e2e/solid-start/basic-solid-query/src/routes/deferred.tsx @@ -0,0 +1,54 @@ +import { createFileRoute } from '@tanstack/solid-router' +import { queryOptions, useQuery } from '@tanstack/solid-query' +import { Suspense, createSignal } from 'solid-js' + +const deferredQueryOptions = () => + queryOptions({ + queryKey: ['deferred'], + queryFn: async () => { + await new Promise((r) => setTimeout(r, 3000)) + return { + message: `Hello deferred from the server!`, + status: 'success', + time: new Date(), + } + }, + }) + +export const Route = createFileRoute('/deferred')({ + loader: ({ context }) => { + // Kick off loading as early as possible! + context.queryClient.prefetchQuery(deferredQueryOptions()) + }, + component: Deferred, +}) + +function Deferred() { + const [count, setCount] = createSignal(0) + + return ( +
+ + + +
Count: {count()}
+
+ +
+
+ ) +} + +function DeferredQuery() { + const deferredQuery = useQuery(() => deferredQueryOptions()) + const data = () => deferredQuery.data + + return ( +
+

Deferred Query

+
Status: {data()?.status ?? 'loading...'}
+
Message: {data()?.message ?? ''}
+
Time: {data() ? new Date(data()!.time).toISOString() : ''}
+
+ ) +} \ No newline at end of file diff --git a/e2e/solid-start/basic-solid-query/src/routes/index.tsx b/e2e/solid-start/basic-solid-query/src/routes/index.tsx new file mode 100644 index 0000000000..ab597c885d --- /dev/null +++ b/e2e/solid-start/basic-solid-query/src/routes/index.tsx @@ -0,0 +1,13 @@ +import { createFileRoute } from '@tanstack/solid-router' + +export const Route = createFileRoute('/')({ + component: Home, +}) + +function Home() { + return ( +
+

Welcome Home!

+
+ ) +} \ No newline at end of file diff --git a/e2e/solid-start/basic-solid-query/src/routes/posts.$postId.tsx b/e2e/solid-start/basic-solid-query/src/routes/posts.$postId.tsx new file mode 100644 index 0000000000..6bc5e644e8 --- /dev/null +++ b/e2e/solid-start/basic-solid-query/src/routes/posts.$postId.tsx @@ -0,0 +1,27 @@ +import { useQuery } from '@tanstack/solid-query' +import { ErrorComponent, createFileRoute } from '@tanstack/solid-router' +import { postQueryOptions } from '~/utils/posts' + +export const Route = createFileRoute('/posts/$postId')({ + loader: async ({ context, params }) => { + await context.queryClient.ensureQueryData(postQueryOptions(params.postId)) + }, + errorComponent: PostErrorComponent, + component: PostComponent, +}) + +export function PostErrorComponent({ error }: { error: any }) { + return +} + +function PostComponent() { + const params = Route.useParams() + const postQuery = useQuery(() => postQueryOptions(params().postId)) + + return ( +
+

{postQuery.data?.title}

+
{postQuery.data?.body}
+
+ ) +} \ No newline at end of file diff --git a/e2e/solid-start/basic-solid-query/src/routes/posts.index.tsx b/e2e/solid-start/basic-solid-query/src/routes/posts.index.tsx new file mode 100644 index 0000000000..70a2ce932e --- /dev/null +++ b/e2e/solid-start/basic-solid-query/src/routes/posts.index.tsx @@ -0,0 +1,9 @@ +import { createFileRoute } from '@tanstack/solid-router' + +export const Route = createFileRoute('/posts/')({ + component: PostsIndexComponent, +}) + +function PostsIndexComponent() { + return
Select a post.
+} \ No newline at end of file diff --git a/e2e/solid-start/basic-solid-query/src/routes/posts.tsx b/e2e/solid-start/basic-solid-query/src/routes/posts.tsx new file mode 100644 index 0000000000..0e46c8c569 --- /dev/null +++ b/e2e/solid-start/basic-solid-query/src/routes/posts.tsx @@ -0,0 +1,48 @@ +import { useQuery } from '@tanstack/solid-query' +import { Link, Outlet, createFileRoute } from '@tanstack/solid-router' +import { For, Suspense } from 'solid-js' +import { postsQueryOptions } from '~/utils/posts' + +export const Route = createFileRoute('/posts')({ + loader: async ({ context }) => { + await context.queryClient.ensureQueryData(postsQueryOptions()) + }, + head: () => ({ meta: [{ title: 'Posts' }] }), + component: PostsComponent, +}) + +function PostsComponent() { + const postsQuery = useQuery(() => postsQueryOptions()) + + return ( +
+
    + Loading posts...
}> + + {(post) => ( +
  • + +
    {post.title.substring(0, 20)}
    + +
  • + )} +
    + + +
    + + + ) +} \ No newline at end of file diff --git a/e2e/solid-start/basic-solid-query/src/routes/users.$userId.tsx b/e2e/solid-start/basic-solid-query/src/routes/users.$userId.tsx new file mode 100644 index 0000000000..3fc005838d --- /dev/null +++ b/e2e/solid-start/basic-solid-query/src/routes/users.$userId.tsx @@ -0,0 +1,34 @@ +import { useQuery } from '@tanstack/solid-query' +import { ErrorComponent, createFileRoute } from '@tanstack/solid-router' +import type { ErrorComponentProps } from '@tanstack/solid-router' + +import { NotFound } from '~/components/NotFound' +import { userQueryOptions } from '~/utils/users' + +export const Route = createFileRoute('/users/$userId')({ + loader: async ({ context, params: { userId } }) => { + await context.queryClient.ensureQueryData(userQueryOptions(userId)) + }, + errorComponent: UserErrorComponent, + component: UserComponent, + notFoundComponent: () => { + return User not found + }, +}) + +export function UserErrorComponent(props: ErrorComponentProps) { + return +} + +function UserComponent() { + const params = Route.useParams() + const userQuery = useQuery(() => userQueryOptions(params().userId)) + const user = () => userQuery.data + + return ( +
    +

    {user()?.name ?? 'loading...'}

    +
    {user()?.email ?? ''}
    +
    + ) +} \ No newline at end of file diff --git a/e2e/solid-start/basic-solid-query/src/routes/users.index.tsx b/e2e/solid-start/basic-solid-query/src/routes/users.index.tsx new file mode 100644 index 0000000000..4943ea7586 --- /dev/null +++ b/e2e/solid-start/basic-solid-query/src/routes/users.index.tsx @@ -0,0 +1,9 @@ +import { createFileRoute } from '@tanstack/solid-router' + +export const Route = createFileRoute('/users/')({ + component: UsersIndexComponent, +}) + +function UsersIndexComponent() { + return
    Select a user.
    +} \ No newline at end of file diff --git a/e2e/solid-start/basic-solid-query/src/routes/users.tsx b/e2e/solid-start/basic-solid-query/src/routes/users.tsx new file mode 100644 index 0000000000..091b75a4d9 --- /dev/null +++ b/e2e/solid-start/basic-solid-query/src/routes/users.tsx @@ -0,0 +1,46 @@ +import { useQuery } from '@tanstack/solid-query' +import { Link, Outlet, createFileRoute } from '@tanstack/solid-router' +import { For } from 'solid-js' + +import { usersQueryOptions } from '~/utils/users' + +export const Route = createFileRoute('/users')({ + loader: async ({ context }) => { + await context.queryClient.ensureQueryData(usersQueryOptions()) + }, + component: UsersComponent, +}) + +function UsersComponent() { + const usersQuery = useQuery(() => usersQueryOptions()) + + return ( +
    +
      + + {(user) => ( +
    • + +
      {user.name}
      + +
    • + )} +
      +
    +
    + +
    + ) +} \ No newline at end of file diff --git a/e2e/solid-start/basic-solid-query/src/styles/app.css b/e2e/solid-start/basic-solid-query/src/styles/app.css new file mode 100644 index 0000000000..5a98003653 --- /dev/null +++ b/e2e/solid-start/basic-solid-query/src/styles/app.css @@ -0,0 +1,8 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +body { + @apply text-base; + font-family: system-ui, sans-serif; +} \ No newline at end of file diff --git a/e2e/solid-start/basic-solid-query/src/utils/posts.tsx b/e2e/solid-start/basic-solid-query/src/utils/posts.tsx new file mode 100644 index 0000000000..88013e8c82 --- /dev/null +++ b/e2e/solid-start/basic-solid-query/src/utils/posts.tsx @@ -0,0 +1,33 @@ +import { queryOptions } from '@tanstack/solid-query' +import axios from 'redaxios' + +export type PostType = { + id: string + title: string + body: string +} + +export const postsQueryOptions = () => + queryOptions({ + queryKey: ['posts'], + queryFn: async () => { + console.info('Fetching posts...') + await new Promise((r) => setTimeout(r, 500)) + return axios + .get>('https://jsonplaceholder.typicode.com/posts') + .then((r) => r.data.slice(0, 10)) + }, + }) + +export const postQueryOptions = (postId: string) => + queryOptions({ + queryKey: ['posts', postId], + queryFn: async () => { + console.info(`Fetching post with id ${postId}...`) + await new Promise((r) => setTimeout(r, 500)) + + return axios + .get(`https://jsonplaceholder.typicode.com/posts/${postId}`) + .then((r) => r.data) + }, + }) \ No newline at end of file diff --git a/e2e/solid-start/basic-solid-query/src/utils/seo.ts b/e2e/solid-start/basic-solid-query/src/utils/seo.ts new file mode 100644 index 0000000000..60e0fcf8e7 --- /dev/null +++ b/e2e/solid-start/basic-solid-query/src/utils/seo.ts @@ -0,0 +1,30 @@ +export function seo(params: { + title: string + description?: string + keywords?: string + image?: string +}) { + const { title, description, keywords, image } = params + + 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 +} \ No newline at end of file diff --git a/e2e/solid-start/basic-solid-query/src/utils/users.tsx b/e2e/solid-start/basic-solid-query/src/utils/users.tsx new file mode 100644 index 0000000000..5811147c40 --- /dev/null +++ b/e2e/solid-start/basic-solid-query/src/utils/users.tsx @@ -0,0 +1,37 @@ +import { queryOptions } from '@tanstack/solid-query' +import axios from 'redaxios' + +export type User = { + id: number + name: string + email: string +} + +const PORT = + import.meta.env.VITE_SERVER_PORT || process.env.VITE_SERVER_PORT || 3000 + +export const DEPLOY_URL = `http://localhost:${PORT}` + +export const usersQueryOptions = () => + queryOptions({ + queryKey: ['users'], + queryFn: () => + axios + .get>(DEPLOY_URL + '/api/users') + .then((r) => r.data) + .catch(() => { + throw new Error('Failed to fetch users') + }), + }) + +export const userQueryOptions = (id: string) => + queryOptions({ + queryKey: ['users', id], + queryFn: () => + axios + .get(DEPLOY_URL + '/api/users/' + id) + .then((r) => r.data) + .catch(() => { + throw new Error('Failed to fetch user') + }), + }) \ No newline at end of file diff --git a/e2e/solid-start/basic-solid-query/tailwind.config.mjs b/e2e/solid-start/basic-solid-query/tailwind.config.mjs new file mode 100644 index 0000000000..f2cff365ba --- /dev/null +++ b/e2e/solid-start/basic-solid-query/tailwind.config.mjs @@ -0,0 +1,8 @@ +/** @type {import('tailwindcss').Config} */ +export default { + content: ['./src/**/*.{js,jsx,ts,tsx}'], + theme: { + extend: {}, + }, + plugins: [], +} \ No newline at end of file diff --git a/e2e/solid-start/basic-solid-query/tests/app.spec.ts b/e2e/solid-start/basic-solid-query/tests/app.spec.ts new file mode 100644 index 0000000000..976f49ca4b --- /dev/null +++ b/e2e/solid-start/basic-solid-query/tests/app.spec.ts @@ -0,0 +1,36 @@ +import { expect, test } from '@playwright/test' + +test('Navigating to post', async ({ page }) => { + await page.goto('/') + + await page.getByRole('link', { name: 'Posts' }).click() + await page.getByRole('link', { name: 'sunt aut facere repe' }).click() + await page.getByRole('link', { name: 'Deep View' }).click() + await expect(page.getByRole('heading')).toContainText('sunt aut facere') +}) + +test('Navigating to user', async ({ page }) => { + await page.goto('/') + + await page.getByRole('link', { name: 'Users' }).click() + await page.getByRole('link', { name: 'Leanne Graham' }).click() + await expect(page.getByRole('heading')).toContainText('Leanne Graham') +}) + +test('Navigating nested layouts', async ({ page }) => { + await page.goto('/') + + await page.getByRole('link', { name: 'Layout', exact: true }).click() + await page.getByRole('link', { name: 'Layout A' }).click() + await expect(page.locator('body')).toContainText("I'm A!") + await page.getByRole('link', { name: 'Layout B' }).click() + await expect(page.locator('body')).toContainText("I'm B!") +}) + +test('Navigating to a not-found route', async ({ page }) => { + await page.goto('/') + + await page.getByRole('link', { name: 'This Route Does Not Exist' }).click() + await page.getByRole('link', { name: 'Start Over' }).click() + await expect(page.getByRole('heading')).toContainText('Welcome Home!') +}) \ No newline at end of file diff --git a/e2e/solid-start/basic-solid-query/tests/setup/global.setup.ts b/e2e/solid-start/basic-solid-query/tests/setup/global.setup.ts new file mode 100644 index 0000000000..03c095d5fc --- /dev/null +++ b/e2e/solid-start/basic-solid-query/tests/setup/global.setup.ts @@ -0,0 +1 @@ +export default function () {} \ No newline at end of file diff --git a/e2e/solid-start/basic-solid-query/tests/setup/global.teardown.ts b/e2e/solid-start/basic-solid-query/tests/setup/global.teardown.ts new file mode 100644 index 0000000000..03c095d5fc --- /dev/null +++ b/e2e/solid-start/basic-solid-query/tests/setup/global.teardown.ts @@ -0,0 +1 @@ +export default function () {} \ No newline at end of file diff --git a/e2e/solid-start/basic-solid-query/tsconfig.json b/e2e/solid-start/basic-solid-query/tsconfig.json new file mode 100644 index 0000000000..88ba4e9537 --- /dev/null +++ b/e2e/solid-start/basic-solid-query/tsconfig.json @@ -0,0 +1,24 @@ +{ + "include": ["**/*.ts", "**/*.tsx"], + "compilerOptions": { + "strict": true, + "esModuleInterop": true, + "jsx": "preserve", + "jsxImportSource": "solid-js", + "module": "ESNext", + "moduleResolution": "Bundler", + "lib": ["DOM", "DOM.Iterable", "ES2022"], + "isolatedModules": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "target": "ES2022", + "allowJs": true, + "forceConsistentCasingInFileNames": true, + "baseUrl": ".", + "paths": { + "~/*": ["./src/*"] + }, + "noEmit": true, + "types": ["vite/client"] + } +} \ No newline at end of file diff --git a/e2e/solid-start/basic-solid-query/vite.config.ts b/e2e/solid-start/basic-solid-query/vite.config.ts new file mode 100644 index 0000000000..37ea52c2f9 --- /dev/null +++ b/e2e/solid-start/basic-solid-query/vite.config.ts @@ -0,0 +1,14 @@ +import { defineConfig } from 'vite' +import tsConfigPaths from 'vite-tsconfig-paths' +import { tanstackStart } from '@tanstack/solid-start/plugin/vite' +import solid from 'vite-plugin-solid' + +export default defineConfig({ + plugins: [ + tsConfigPaths({ + projects: ['./tsconfig.json'], + }), + tanstackStart(), + solid({ ssr: true }), + ], +}) \ No newline at end of file diff --git a/e2e/solid-start/query-integration/package.json b/e2e/solid-start/query-integration/package.json new file mode 100644 index 0000000000..f37c196dd1 --- /dev/null +++ b/e2e/solid-start/query-integration/package.json @@ -0,0 +1,36 @@ +{ + "name": "tanstack-solid-start-e2e-query-integration", + "private": true, + "sideEffects": false, + "type": "module", + "scripts": { + "dev": "vite dev --port 3000", + "dev:e2e": "vite dev", + "build": "vite build && tsc --noEmit", + "start": "pnpx srvx --prod -s ../client dist/server/server.js", + "test:e2e": "rm -rf port*.txt; playwright test --project=chromium" + }, + "dependencies": { + "@tanstack/solid-query": "^5.66.0", + "@tanstack/solid-query-devtools": "^5.66.0", + "@tanstack/solid-router": "workspace:^", + "@tanstack/solid-router-devtools": "workspace:^", + "@tanstack/solid-router-ssr-query": "workspace:^", + "@tanstack/solid-start": "workspace:^", + "solid-js": "^1.9.5", + "tailwind-merge": "^2.6.0", + "vite": "^7.1.7", + "zod": "^3.24.2" + }, + "devDependencies": { + "@playwright/test": "^1.50.1", + "@tanstack/router-e2e-utils": "workspace:^", + "@types/node": "^22.10.2", + "autoprefixer": "^10.4.20", + "postcss": "^8.5.1", + "tailwindcss": "^3.4.17", + "typescript": "^5.7.2", + "vite-plugin-solid": "^2.11.8", + "vite-tsconfig-paths": "^5.1.4" + } +} \ No newline at end of file diff --git a/e2e/solid-start/query-integration/playwright.config.ts b/e2e/solid-start/query-integration/playwright.config.ts new file mode 100644 index 0000000000..ae6bbca58e --- /dev/null +++ b/e2e/solid-start/query-integration/playwright.config.ts @@ -0,0 +1,36 @@ +import { defineConfig, devices } from '@playwright/test' +import { + getDummyServerPort, + getTestServerPort, +} from '@tanstack/router-e2e-utils' +import packageJson from './package.json' with { type: 'json' } + +const PORT = await getTestServerPort(packageJson.name) +const EXTERNAL_PORT = await getDummyServerPort(packageJson.name) + +const baseURL = `http://localhost:${PORT}` + +export default defineConfig({ + testDir: './tests', + workers: 1, + + reporter: [['line']], + + use: { + baseURL, + }, + + webServer: { + command: `VITE_NODE_ENV="test" VITE_EXTERNAL_PORT=${EXTERNAL_PORT} VITE_SERVER_PORT=${PORT} pnpm build && VITE_NODE_ENV="test" VITE_EXTERNAL_PORT=${EXTERNAL_PORT} PORT=${PORT} VITE_SERVER_PORT=${PORT} pnpm start`, + url: baseURL, + reuseExistingServer: !process.env.CI, + stdout: 'pipe', + }, + + projects: [ + { + name: 'chromium', + use: { ...devices['Desktop Chrome'] }, + }, + ], +}) \ No newline at end of file diff --git a/e2e/solid-start/query-integration/postcss.config.mjs b/e2e/solid-start/query-integration/postcss.config.mjs new file mode 100644 index 0000000000..e99ebc2c0e --- /dev/null +++ b/e2e/solid-start/query-integration/postcss.config.mjs @@ -0,0 +1,6 @@ +export default { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +} \ No newline at end of file diff --git a/e2e/solid-start/query-integration/src/queryOptions.ts b/e2e/solid-start/query-integration/src/queryOptions.ts new file mode 100644 index 0000000000..77385e7987 --- /dev/null +++ b/e2e/solid-start/query-integration/src/queryOptions.ts @@ -0,0 +1,16 @@ +import { queryOptions } from '@tanstack/solid-query' + +export const makeQueryOptions = (key: string) => + queryOptions({ + queryKey: ['e2e-test-query-integration', key], + queryFn: async () => { + console.log('fetching query data') + await new Promise((resolve) => { + setTimeout(resolve, 500) + }) + const result = typeof window !== 'undefined' ? 'client' : 'server' + console.log('query data result', result) + return result + }, + staleTime: Infinity, + }) \ No newline at end of file diff --git a/e2e/solid-start/query-integration/src/routeTree.gen.ts b/e2e/solid-start/query-integration/src/routeTree.gen.ts new file mode 100644 index 0000000000..bdd2163038 --- /dev/null +++ b/e2e/solid-start/query-integration/src/routeTree.gen.ts @@ -0,0 +1,104 @@ +/* eslint-disable */ + +// @ts-nocheck + +// noinspection JSUnusedGlobalSymbols + +// This file was automatically generated by TanStack Router. +// You should NOT make any changes in this file as it will be overwritten. +// 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 UseQueryRouteImport } from './routes/useQuery' +import { Route as IndexRouteImport } from './routes/index' +import { Route as LoaderFetchQueryTypeRouteImport } from './routes/loader-fetchQuery/$type' + +const UseQueryRoute = UseQueryRouteImport.update({ + id: '/useQuery', + path: '/useQuery', + getParentRoute: () => rootRouteImport, +} as any) +const IndexRoute = IndexRouteImport.update({ + id: '/', + path: '/', + getParentRoute: () => rootRouteImport, +} as any) +const LoaderFetchQueryTypeRoute = LoaderFetchQueryTypeRouteImport.update({ + id: '/loader-fetchQuery/$type', + path: '/loader-fetchQuery/$type', + getParentRoute: () => rootRouteImport, +} as any) + +export interface FileRoutesByFullPath { + '/': typeof IndexRoute + '/useQuery': typeof UseQueryRoute + '/loader-fetchQuery/$type': typeof LoaderFetchQueryTypeRoute +} +export interface FileRoutesByTo { + '/': typeof IndexRoute + '/useQuery': typeof UseQueryRoute + '/loader-fetchQuery/$type': typeof LoaderFetchQueryTypeRoute +} +export interface FileRoutesById { + __root__: typeof rootRouteImport + '/': typeof IndexRoute + '/useQuery': typeof UseQueryRoute + '/loader-fetchQuery/$type': typeof LoaderFetchQueryTypeRoute +} +export interface FileRouteTypes { + fileRoutesByFullPath: FileRoutesByFullPath + fullPaths: '/' | '/useQuery' | '/loader-fetchQuery/$type' + fileRoutesByTo: FileRoutesByTo + to: '/' | '/useQuery' | '/loader-fetchQuery/$type' + id: '__root__' | '/' | '/useQuery' | '/loader-fetchQuery/$type' + fileRoutesById: FileRoutesById +} +export interface RootRouteChildren { + IndexRoute: typeof IndexRoute + UseQueryRoute: typeof UseQueryRoute + LoaderFetchQueryTypeRoute: typeof LoaderFetchQueryTypeRoute +} + +declare module '@tanstack/solid-router' { + interface FileRoutesByPath { + '/useQuery': { + id: '/useQuery' + path: '/useQuery' + fullPath: '/useQuery' + preLoaderRoute: typeof UseQueryRouteImport + parentRoute: typeof rootRouteImport + } + '/': { + id: '/' + path: '/' + fullPath: '/' + preLoaderRoute: typeof IndexRouteImport + parentRoute: typeof rootRouteImport + } + '/loader-fetchQuery/$type': { + id: '/loader-fetchQuery/$type' + path: '/loader-fetchQuery/$type' + fullPath: '/loader-fetchQuery/$type' + preLoaderRoute: typeof LoaderFetchQueryTypeRouteImport + parentRoute: typeof rootRouteImport + } + } +} + +const rootRouteChildren: RootRouteChildren = { + IndexRoute: IndexRoute, + UseQueryRoute: UseQueryRoute, + LoaderFetchQueryTypeRoute: LoaderFetchQueryTypeRoute, +} +export const routeTree = rootRouteImport + ._addFileChildren(rootRouteChildren) + ._addFileTypes() + +import type { getRouter } from './router.tsx' +import type { createStart } from '@tanstack/solid-start' +declare module '@tanstack/solid-start' { + interface Register { + ssr: true + router: Awaited> + } +} diff --git a/e2e/solid-start/query-integration/src/router.tsx b/e2e/solid-start/query-integration/src/router.tsx new file mode 100644 index 0000000000..936abb1ea4 --- /dev/null +++ b/e2e/solid-start/query-integration/src/router.tsx @@ -0,0 +1,26 @@ +import { QueryClient } from '@tanstack/solid-query' +import { createRouter } from '@tanstack/solid-router' +import { setupRouterSsrQueryIntegration } from '@tanstack/solid-router-ssr-query' +import { routeTree } from './routeTree.gen' + +export function getRouter() { + const queryClient = new QueryClient({ + defaultOptions: { + queries: { + // Enable only on client to avoid hydration mismatches + experimental_prefetchInRender: typeof window !== 'undefined', + }, + }, + }) + const router = createRouter({ + routeTree, + context: { queryClient }, + scrollRestoration: true, + defaultPreload: 'intent', + }) + setupRouterSsrQueryIntegration({ + router, + queryClient, + }) + return router +} \ No newline at end of file diff --git a/e2e/solid-start/query-integration/src/routes/__root.tsx b/e2e/solid-start/query-integration/src/routes/__root.tsx new file mode 100644 index 0000000000..3860622760 --- /dev/null +++ b/e2e/solid-start/query-integration/src/routes/__root.tsx @@ -0,0 +1,84 @@ +/// +import { + HeadContent, + Link, + Scripts, + createRootRouteWithContext, +} from '@tanstack/solid-router' +import { TanStackRouterDevtoolsInProd } from '@tanstack/solid-router-devtools' +import type { QueryClient } from '@tanstack/solid-query' +import appCss from '~/styles/app.css?url' + +export const Route = createRootRouteWithContext<{ + queryClient: QueryClient +}>()({ + head: () => ({ + meta: [ + { + charset: 'utf-8', + }, + ], + links: [{ rel: 'stylesheet', href: appCss }], + }), + shellComponent: RootDocument, +}) + +function RootDocument(props: { children?: any }) { + return ( + + + + + +
    + + Home + {' '} + + fetchQuery (sync) + {' '} + + fetchQuery (async) + {' '} + + useQuery + {' '} + {/* + useSuspenseQuery + {' '} */} +
    +
    + {props.children} + + + + + ) +} \ No newline at end of file diff --git a/e2e/solid-start/query-integration/src/routes/index.tsx b/e2e/solid-start/query-integration/src/routes/index.tsx new file mode 100644 index 0000000000..93a143cc2d --- /dev/null +++ b/e2e/solid-start/query-integration/src/routes/index.tsx @@ -0,0 +1,13 @@ +import { createFileRoute } from '@tanstack/solid-router' + +export const Route = createFileRoute('/')({ + component: Home, +}) + +function Home() { + return ( +
    +

    Query Integration E2E tests

    +
    + ) +} \ No newline at end of file diff --git a/e2e/solid-start/query-integration/src/routes/loader-fetchQuery/$type.tsx b/e2e/solid-start/query-integration/src/routes/loader-fetchQuery/$type.tsx new file mode 100644 index 0000000000..ebd34b63f9 --- /dev/null +++ b/e2e/solid-start/query-integration/src/routes/loader-fetchQuery/$type.tsx @@ -0,0 +1,45 @@ +import { useQuery } from '@tanstack/solid-query' +import { createFileRoute } from '@tanstack/solid-router' +import z from 'zod' +import { makeQueryOptions } from '~/queryOptions' + +export const Route = createFileRoute('/loader-fetchQuery/$type')({ + component: RouteComponent, + params: { + parse: ({ type }) => + z + .object({ + type: z.union([z.literal('sync'), z.literal('async')]), + }) + .parse({ type }), + }, + context: ({ params }) => ({ + queryOptions: makeQueryOptions(`loader-fetchQuery-${params.type}`), + }), + loader: async ({ context, params }) => { + await context.queryClient.ensureQueryData(context.queryOptions) + if (params.type === 'sync') { + return context.queryClient.getQueryData(context.queryOptions.queryKey) as string + } + return undefined as any + }, +}) + +function RouteComponent() { + const params = Route.useParams() + const loaderData = Route.useLoaderData() + const query = useQuery(() => { + return makeQueryOptions(`loader-fetchQuery-${params().type}`) + }) + + return ( +
    +
    + loader data:
    {loaderData() ?? 'undefined'}
    +
    +
    + query data:
    {query.data ?? 'loading...'}
    +
    +
    + ) +} \ No newline at end of file diff --git a/e2e/solid-start/query-integration/src/routes/useQuery.tsx b/e2e/solid-start/query-integration/src/routes/useQuery.tsx new file mode 100644 index 0000000000..f4a2103f70 --- /dev/null +++ b/e2e/solid-start/query-integration/src/routes/useQuery.tsx @@ -0,0 +1,23 @@ +import { useQuery } from '@tanstack/solid-query' +import { createFileRoute } from '@tanstack/solid-router' +import { makeQueryOptions } from '~/queryOptions' + +const qOptions = makeQueryOptions('useQuery') + +export const Route = createFileRoute('/useQuery')({ + loader: async ({ context }) => { + await context.queryClient.ensureQueryData(qOptions) + }, + component: RouteComponent, +}) + +function RouteComponent() { + const query = useQuery(() => qOptions) + return ( +
    +
    + query data:
    {query.data ?? 'loading...'}
    +
    +
    + ) +} \ No newline at end of file diff --git a/e2e/solid-start/query-integration/src/styles/app.css b/e2e/solid-start/query-integration/src/styles/app.css new file mode 100644 index 0000000000..5a98003653 --- /dev/null +++ b/e2e/solid-start/query-integration/src/styles/app.css @@ -0,0 +1,8 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +body { + @apply text-base; + font-family: system-ui, sans-serif; +} \ No newline at end of file diff --git a/e2e/solid-start/query-integration/tailwind.config.mjs b/e2e/solid-start/query-integration/tailwind.config.mjs new file mode 100644 index 0000000000..f2cff365ba --- /dev/null +++ b/e2e/solid-start/query-integration/tailwind.config.mjs @@ -0,0 +1,8 @@ +/** @type {import('tailwindcss').Config} */ +export default { + content: ['./src/**/*.{js,jsx,ts,tsx}'], + theme: { + extend: {}, + }, + plugins: [], +} \ No newline at end of file diff --git a/e2e/solid-start/query-integration/tests/app.spec.ts b/e2e/solid-start/query-integration/tests/app.spec.ts new file mode 100644 index 0000000000..90b7f8deb2 --- /dev/null +++ b/e2e/solid-start/query-integration/tests/app.spec.ts @@ -0,0 +1,34 @@ +import { expect } from '@playwright/test' +import { test } from '@tanstack/router-e2e-utils' + +test.describe('queries are streamed from the server', () => { + test('direct visit - loader on server runs fetchQuery and awaits it', async ({ + page, + }) => { + await page.goto('/loader-fetchQuery/sync') + + const queryData = page.getByTestId('query-data') + await expect(queryData).toHaveText('server') + + const loaderData = page.getByTestId('loader-data') + await expect(loaderData).toHaveText('server') + }) + test('direct visit - loader on server runs fetchQuery and does not await it', async ({ + page, + }) => { + await page.goto('/loader-fetchQuery/async') + + const queryData = page.getByTestId('query-data') + await expect(queryData).toHaveText('server') + + const loaderData = page.getByTestId('loader-data') + await expect(loaderData).toHaveText('undefined') + }) + + test('useQuery', async ({ page }) => { + await page.goto('/useQuery') + + const queryData = page.getByTestId('query-data') + await expect(queryData).toHaveText('server') + }) +}) diff --git a/e2e/solid-start/query-integration/tsconfig.json b/e2e/solid-start/query-integration/tsconfig.json new file mode 100644 index 0000000000..88ba4e9537 --- /dev/null +++ b/e2e/solid-start/query-integration/tsconfig.json @@ -0,0 +1,24 @@ +{ + "include": ["**/*.ts", "**/*.tsx"], + "compilerOptions": { + "strict": true, + "esModuleInterop": true, + "jsx": "preserve", + "jsxImportSource": "solid-js", + "module": "ESNext", + "moduleResolution": "Bundler", + "lib": ["DOM", "DOM.Iterable", "ES2022"], + "isolatedModules": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "target": "ES2022", + "allowJs": true, + "forceConsistentCasingInFileNames": true, + "baseUrl": ".", + "paths": { + "~/*": ["./src/*"] + }, + "noEmit": true, + "types": ["vite/client"] + } +} \ No newline at end of file diff --git a/e2e/solid-start/query-integration/vite.config.ts b/e2e/solid-start/query-integration/vite.config.ts new file mode 100644 index 0000000000..37ea52c2f9 --- /dev/null +++ b/e2e/solid-start/query-integration/vite.config.ts @@ -0,0 +1,14 @@ +import { defineConfig } from 'vite' +import tsConfigPaths from 'vite-tsconfig-paths' +import { tanstackStart } from '@tanstack/solid-start/plugin/vite' +import solid from 'vite-plugin-solid' + +export default defineConfig({ + plugins: [ + tsConfigPaths({ + projects: ['./tsconfig.json'], + }), + tanstackStart(), + solid({ ssr: true }), + ], +}) \ No newline at end of file diff --git a/package.json b/package.json index ebf7008739..2d5daa7d8b 100644 --- a/package.json +++ b/package.json @@ -95,6 +95,7 @@ "@tanstack/router-vite-plugin": "workspace:*", "@tanstack/router-ssr-query-core": "workspace:*", "@tanstack/react-router-ssr-query": "workspace:*", + "@tanstack/solid-router-ssr-query": "workspace:*", "@tanstack/zod-adapter": "workspace:*", "@tanstack/valibot-adapter": "workspace:*", "@tanstack/arktype-adapter": "workspace:*", diff --git a/packages/solid-router-ssr-query/README.md b/packages/solid-router-ssr-query/README.md new file mode 100644 index 0000000000..d0a08dc3e5 --- /dev/null +++ b/packages/solid-router-ssr-query/README.md @@ -0,0 +1,38 @@ +# @tanstack/solid-router-ssr-query + +SSR query integration for TanStack Solid Router and TanStack Solid Query. + +This package provides seamless integration between TanStack Router and TanStack Query for server-side rendering in Solid applications. + +## Installation + +```bash +npm install @tanstack/solid-router-ssr-query +# or +pnpm add @tanstack/solid-router-ssr-query +# or +yarn add @tanstack/solid-router-ssr-query +``` + +## Usage + +```tsx +import { QueryClient } from '@tanstack/solid-query' +import { createRouter } from '@tanstack/solid-router' +import { setupRouterSsrQueryIntegration } from '@tanstack/solid-router-ssr-query' + +const queryClient = new QueryClient() +const router = createRouter({ + routeTree, + context: { queryClient }, +}) + +setupRouterSsrQueryIntegration({ + router, + queryClient, +}) +``` + +## License + +MIT \ No newline at end of file diff --git a/packages/solid-router-ssr-query/eslint.config.js b/packages/solid-router-ssr-query/eslint.config.js new file mode 100644 index 0000000000..381a097af3 --- /dev/null +++ b/packages/solid-router-ssr-query/eslint.config.js @@ -0,0 +1,12 @@ +// @ts-check + +import pluginSolid from 'eslint-plugin-solid/configs/typescript' +import rootConfig from '../../eslint.config.js' + +export default [ + ...rootConfig, + { + files: ['**/*.{ts,tsx}'], + ...pluginSolid, + }, +] \ No newline at end of file diff --git a/packages/solid-router-ssr-query/package.json b/packages/solid-router-ssr-query/package.json new file mode 100644 index 0000000000..2cf8bea6e5 --- /dev/null +++ b/packages/solid-router-ssr-query/package.json @@ -0,0 +1,81 @@ +{ + "name": "@tanstack/solid-router-ssr-query", + "version": "1.132.25", + "description": "Modern and scalable routing for Solid applications", + "author": "Tanner Linsley", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/TanStack/router.git", + "directory": "packages/solid-router-ssr-query" + }, + "homepage": "https://tanstack.com/router", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "keywords": [ + "solidjs", + "location", + "router", + "routing", + "async", + "async router", + "typescript" + ], + "scripts": { + "clean": "rimraf ./dist && rimraf ./coverage", + "test:eslint": "eslint ./src", + "test:types": "pnpm run \"/^test:types:ts[0-9]{2}$/\"", + "test:types:ts54": "node ../../node_modules/typescript54/lib/tsc.js", + "test:types:ts55": "node ../../node_modules/typescript55/lib/tsc.js", + "test:types:ts56": "node ../../node_modules/typescript56/lib/tsc.js", + "test:types:ts57": "node ../../node_modules/typescript57/lib/tsc.js", + "test:types:ts58": "node ../../node_modules/typescript58/lib/tsc.js", + "test:types:ts59": "tsc", + "test:unit": "exit 0; vitest", + "test:unit:dev": "pnpm run test:unit --watch", + "test:build": "publint --strict && attw --ignore-rules no-resolution --pack .", + "build": "vite build" + }, + "type": "module", + "types": "dist/esm/index.d.ts", + "main": "dist/cjs/index.cjs", + "module": "dist/esm/index.js", + "exports": { + ".": { + "import": { + "types": "./dist/esm/index.d.ts", + "default": "./dist/esm/index.js" + }, + "require": { + "types": "./dist/cjs/index.d.cts", + "default": "./dist/cjs/index.cjs" + } + }, + "./package.json": "./package.json" + }, + "sideEffects": false, + "files": [ + "dist", + "src" + ], + "engines": { + "node": ">=12" + }, + "dependencies": { + "@tanstack/router-ssr-query-core": "workspace:*" + }, + "devDependencies": { + "vite-plugin-solid": "^2.11.8", + "solid-js": "^1.9.5", + "@tanstack/solid-router": "workspace:*", + "@tanstack/solid-query": ">=5.66.0" + }, + "peerDependencies": { + "solid-js": "^1.9.5", + "@tanstack/query-core": ">=5.66.0", + "@tanstack/solid-router": ">=1.127.0", + "@tanstack/solid-query": ">=5.66.2" + } +} \ No newline at end of file diff --git a/packages/solid-router-ssr-query/src/index.tsx b/packages/solid-router-ssr-query/src/index.tsx new file mode 100644 index 0000000000..a7630d0a34 --- /dev/null +++ b/packages/solid-router-ssr-query/src/index.tsx @@ -0,0 +1,30 @@ +import { QueryClientProvider } from '@tanstack/solid-query' +import { setupCoreRouterSsrQueryIntegration } from '@tanstack/router-ssr-query-core' +import type { RouterSsrQueryOptions } from '@tanstack/router-ssr-query-core' +import type { AnyRouter } from '@tanstack/solid-router' +import type { JSX } from 'solid-js' + +export type Options = + RouterSsrQueryOptions & { + wrapQueryClient?: boolean + } + +export function setupRouterSsrQueryIntegration( + opts: Options, +) { + setupCoreRouterSsrQueryIntegration(opts) + + if (opts.wrapQueryClient === false) { + return + } + + const OGWrap = opts.router.options.Wrap || ((props: { children: JSX.Element }) => props.children) + + opts.router.options.Wrap = (props) => { + return ( + + {props.children} + + ) + } +} \ No newline at end of file diff --git a/packages/solid-router-ssr-query/tsconfig.json b/packages/solid-router-ssr-query/tsconfig.json new file mode 100644 index 0000000000..cf877483c0 --- /dev/null +++ b/packages/solid-router-ssr-query/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "jsx": "preserve", + "jsxImportSource": "solid-js" + }, + "include": ["src", "tests", "vite.config.ts"] +} \ No newline at end of file diff --git a/packages/solid-router-ssr-query/vite.config.ts b/packages/solid-router-ssr-query/vite.config.ts new file mode 100644 index 0000000000..3c681ed252 --- /dev/null +++ b/packages/solid-router-ssr-query/vite.config.ts @@ -0,0 +1,24 @@ +import { defineConfig, mergeConfig } from 'vitest/config' +import { tanstackViteConfig } from '@tanstack/config/vite' +import solid from 'vite-plugin-solid' +import packageJson from './package.json' +import type { UserConfig } from 'vitest/config' + +const config = defineConfig({ + plugins: [solid()] as UserConfig['plugins'], + test: { + name: packageJson.name, + dir: './tests', + watch: false, + environment: 'jsdom', + typecheck: { enabled: true }, + }, +}) + +export default mergeConfig( + config, + tanstackViteConfig({ + entry: './src/index.tsx', + srcDir: './src', + }), +) \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 032d8235e2..5c09b70596 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -29,6 +29,7 @@ overrides: '@tanstack/router-vite-plugin': workspace:* '@tanstack/router-ssr-query-core': workspace:* '@tanstack/react-router-ssr-query': workspace:* + '@tanstack/solid-router-ssr-query': workspace:* '@tanstack/zod-adapter': workspace:* '@tanstack/valibot-adapter': workspace:* '@tanstack/arktype-adapter': workspace:* @@ -2512,6 +2513,70 @@ importers: specifier: ^5.1.4 version: 5.1.4(typescript@5.8.2)(vite@7.1.7(@types/node@22.10.2)(jiti@2.6.0)(lightningcss@1.30.1)(terser@5.37.0)(tsx@4.20.3)(yaml@2.7.0)) + e2e/solid-start/basic-solid-query: + dependencies: + '@tanstack/solid-query': + specifier: ^5.66.0 + version: 5.72.2(solid-js@1.9.5) + '@tanstack/solid-query-devtools': + specifier: ^5.66.0 + version: 5.72.2(@tanstack/solid-query@5.72.2(solid-js@1.9.5))(solid-js@1.9.5) + '@tanstack/solid-router': + specifier: workspace:^ + version: link:../../../packages/solid-router + '@tanstack/solid-router-devtools': + specifier: workspace:^ + version: link:../../../packages/solid-router-devtools + '@tanstack/solid-router-ssr-query': + specifier: workspace:* + version: link:../../../packages/solid-router-ssr-query + '@tanstack/solid-start': + specifier: workspace:* + version: link:../../../packages/solid-start + redaxios: + specifier: ^0.5.1 + version: 0.5.1 + solid-js: + specifier: ^1.9.5 + version: 1.9.5 + tailwind-merge: + specifier: ^2.6.0 + version: 2.6.0 + vite: + specifier: ^7.1.7 + version: 7.1.7(@types/node@22.10.2)(jiti@2.6.0)(lightningcss@1.30.1)(terser@5.37.0)(tsx@4.20.3)(yaml@2.7.0) + devDependencies: + '@playwright/test': + specifier: ^1.52.0 + version: 1.52.0 + '@tanstack/router-e2e-utils': + specifier: workspace:^ + version: link:../../e2e-utils + '@types/node': + specifier: 22.10.2 + version: 22.10.2 + autoprefixer: + specifier: ^10.4.20 + version: 10.4.20(postcss@8.5.6) + postcss: + specifier: ^8.5.1 + version: 8.5.6 + srvx: + specifier: ^0.8.6 + version: 0.8.7 + tailwindcss: + specifier: ^3.4.17 + version: 3.4.17 + typescript: + specifier: ^5.7.2 + version: 5.9.2 + vite-plugin-solid: + specifier: ^2.11.8 + version: 2.11.8(@testing-library/jest-dom@6.6.3)(solid-js@1.9.5)(vite@7.1.7(@types/node@22.10.2)(jiti@2.6.0)(lightningcss@1.30.1)(terser@5.37.0)(tsx@4.20.3)(yaml@2.7.0)) + vite-tsconfig-paths: + specifier: ^5.1.4 + version: 5.1.4(typescript@5.9.2)(vite@7.1.7(@types/node@22.10.2)(jiti@2.6.0)(lightningcss@1.30.1)(terser@5.37.0)(tsx@4.20.3)(yaml@2.7.0)) + e2e/solid-start/basic-tsr-config: dependencies: '@tanstack/solid-router': @@ -2613,6 +2678,67 @@ importers: specifier: ^5.1.4 version: 5.1.4(typescript@5.8.2)(vite@7.1.7(@types/node@22.10.2)(jiti@2.6.0)(lightningcss@1.30.1)(terser@5.37.0)(tsx@4.20.3)(yaml@2.7.0)) + e2e/solid-start/query-integration: + dependencies: + '@tanstack/solid-query': + specifier: ^5.66.0 + version: 5.72.2(solid-js@1.9.5) + '@tanstack/solid-query-devtools': + specifier: ^5.66.0 + version: 5.72.2(@tanstack/solid-query@5.72.2(solid-js@1.9.5))(solid-js@1.9.5) + '@tanstack/solid-router': + specifier: workspace:^ + version: link:../../../packages/solid-router + '@tanstack/solid-router-devtools': + specifier: workspace:^ + version: link:../../../packages/solid-router-devtools + '@tanstack/solid-router-ssr-query': + specifier: workspace:* + version: link:../../../packages/solid-router-ssr-query + '@tanstack/solid-start': + specifier: workspace:* + version: link:../../../packages/solid-start + solid-js: + specifier: ^1.9.5 + version: 1.9.5 + tailwind-merge: + specifier: ^2.6.0 + version: 2.6.0 + vite: + specifier: ^7.1.7 + version: 7.1.7(@types/node@22.10.2)(jiti@2.6.0)(lightningcss@1.30.1)(terser@5.37.0)(tsx@4.20.3)(yaml@2.7.0) + zod: + specifier: ^3.24.2 + version: 3.25.57 + devDependencies: + '@playwright/test': + specifier: ^1.52.0 + version: 1.52.0 + '@tanstack/router-e2e-utils': + specifier: workspace:^ + version: link:../../e2e-utils + '@types/node': + specifier: 22.10.2 + version: 22.10.2 + autoprefixer: + specifier: ^10.4.20 + version: 10.4.20(postcss@8.5.6) + postcss: + specifier: ^8.5.1 + version: 8.5.6 + tailwindcss: + specifier: ^3.4.17 + version: 3.4.17 + typescript: + specifier: ^5.7.2 + version: 5.9.2 + vite-plugin-solid: + specifier: ^2.11.8 + version: 2.11.8(@testing-library/jest-dom@6.6.3)(solid-js@1.9.5)(vite@7.1.7(@types/node@22.10.2)(jiti@2.6.0)(lightningcss@1.30.1)(terser@5.37.0)(tsx@4.20.3)(yaml@2.7.0)) + vite-tsconfig-paths: + specifier: ^5.1.4 + version: 5.1.4(typescript@5.9.2)(vite@7.1.7(@types/node@22.10.2)(jiti@2.6.0)(lightningcss@1.30.1)(terser@5.37.0)(tsx@4.20.3)(yaml@2.7.0)) + e2e/solid-start/scroll-restoration: dependencies: '@tanstack/solid-router': @@ -7257,6 +7383,28 @@ importers: specifier: ^2.11.8 version: 2.11.8(@testing-library/jest-dom@6.6.3)(solid-js@1.9.5)(vite@7.1.7(@types/node@22.10.2)(jiti@2.6.0)(lightningcss@1.30.1)(terser@5.37.0)(tsx@4.20.3)(yaml@2.7.0)) + packages/solid-router-ssr-query: + dependencies: + '@tanstack/query-core': + specifier: 5.66.0 + version: 5.66.0 + '@tanstack/router-ssr-query-core': + specifier: workspace:* + version: link:../router-ssr-query-core + devDependencies: + '@tanstack/solid-query': + specifier: '>=5.66.0' + version: 5.72.2(solid-js@1.9.5) + '@tanstack/solid-router': + specifier: workspace:* + version: link:../solid-router + solid-js: + specifier: ^1.9.5 + version: 1.9.5 + vite-plugin-solid: + specifier: ^2.11.8 + version: 2.11.8(@testing-library/jest-dom@6.6.3)(solid-js@1.9.5)(vite@7.1.7(@types/node@22.10.2)(jiti@2.6.0)(lightningcss@1.30.1)(terser@5.37.0)(tsx@4.20.3)(yaml@2.7.0)) + packages/solid-start: dependencies: '@tanstack/solid-router': From 2926e7fb92ed684e32462c40b3a1c06f0b467eea Mon Sep 17 00:00:00 2001 From: Brenley Dueck Date: Tue, 30 Sep 2025 21:15:46 -0500 Subject: [PATCH 2/3] fix: basic-solid-query e2e test (#5319) --- .../basic-solid-query/package.json | 2 +- .../playwright-report/index.html | 19551 +++++++++++++++- .../basic-solid-query/playwright.config.ts | 2 +- .../basic-solid-query/postcss.config.mjs | 2 +- .../src/components/DefaultCatchBoundary.tsx | 2 +- .../src/components/NotFound.tsx | 6 +- .../basic-solid-query/src/routeTree.gen.ts | 73 + .../basic-solid-query/src/router.tsx | 2 +- .../basic-solid-query/src/routes/__root.tsx | 2 +- .../basic-solid-query/src/routes/api.users.ts | 25 + .../src/routes/api/users.$id.ts | 31 + .../basic-solid-query/src/routes/deferred.tsx | 2 +- .../basic-solid-query/src/routes/index.tsx | 2 +- .../src/routes/posts.$postId.tsx | 14 +- .../src/routes/posts.index.tsx | 2 +- .../basic-solid-query/src/routes/posts.tsx | 2 +- .../src/routes/posts_.$postId.deep.tsx | 36 + .../src/routes/users.$userId.tsx | 8 +- .../src/routes/users.index.tsx | 2 +- .../basic-solid-query/src/routes/users.tsx | 2 +- .../basic-solid-query/src/styles/app.css | 2 +- .../basic-solid-query/src/utils/posts.tsx | 2 +- .../basic-solid-query/src/utils/seo.ts | 2 +- .../basic-solid-query/src/utils/users.tsx | 2 +- .../basic-solid-query/tailwind.config.mjs | 2 +- .../basic-solid-query/tests/app.spec.ts | 18 - .../tests/setup/global.setup.ts | 7 +- .../tests/setup/global.teardown.ts | 7 +- .../basic-solid-query/tsconfig.json | 2 +- .../basic-solid-query/vite.config.ts | 2 +- .../query-integration/package.json | 2 +- .../query-integration/playwright.config.ts | 2 +- .../query-integration/postcss.config.mjs | 2 +- .../query-integration/src/queryOptions.ts | 2 +- .../query-integration/src/router.tsx | 2 +- .../query-integration/src/routes/__root.tsx | 2 +- .../query-integration/src/routes/index.tsx | 2 +- .../src/routes/loader-fetchQuery/$type.tsx | 12 +- .../query-integration/src/routes/useQuery.tsx | 5 +- .../query-integration/src/styles/app.css | 2 +- .../query-integration/tailwind.config.mjs | 2 +- .../query-integration/tsconfig.json | 2 +- .../query-integration/vite.config.ts | 2 +- packages/solid-router-ssr-query/README.md | 2 +- .../solid-router-ssr-query/eslint.config.js | 2 +- packages/solid-router-ssr-query/package.json | 15 +- packages/solid-router-ssr-query/src/index.tsx | 8 +- packages/solid-router-ssr-query/tsconfig.json | 2 +- .../solid-router-ssr-query/vite.config.ts | 2 +- pnpm-lock.yaml | 23 +- 50 files changed, 19760 insertions(+), 147 deletions(-) create mode 100644 e2e/solid-start/basic-solid-query/src/routes/api.users.ts create mode 100644 e2e/solid-start/basic-solid-query/src/routes/api/users.$id.ts create mode 100644 e2e/solid-start/basic-solid-query/src/routes/posts_.$postId.deep.tsx diff --git a/e2e/solid-start/basic-solid-query/package.json b/e2e/solid-start/basic-solid-query/package.json index 4baacabf7c..5af0b6150a 100644 --- a/e2e/solid-start/basic-solid-query/package.json +++ b/e2e/solid-start/basic-solid-query/package.json @@ -34,4 +34,4 @@ "vite-plugin-solid": "^2.11.8", "vite-tsconfig-paths": "^5.1.4" } -} \ No newline at end of file +} diff --git a/e2e/solid-start/basic-solid-query/playwright-report/index.html b/e2e/solid-start/basic-solid-query/playwright-report/index.html index 2d3e74e45d..98601962cc 100644 --- a/e2e/solid-start/basic-solid-query/playwright-report/index.html +++ b/e2e/solid-start/basic-solid-query/playwright-report/index.html @@ -1,77 +1,19508 @@ - - - - + + - - - + + + Playwright Test Report - - +`.trimStart(), + _0 = ({ error: s, testId: l, context: r }) => + h.jsx($0, { + code: s, + testId: l, + children: + r && + h.jsx('div', { + style: { position: 'absolute', right: 0, padding: '10px' }, + children: h.jsx(lg, { context: r }), + }), + }), + $0 = ({ code: s, children: l, testId: r }) => { + const a = se.useMemo(() => va(s), [s]) + return h.jsxs('div', { + className: 'test-error-container test-error-text', + 'data-testid': r, + children: [ + l, + h.jsx('div', { + className: 'test-error-view', + dangerouslySetInnerHTML: { __html: a || '' }, + }), + ], + }) + }, + lg = ({ context: s }) => { + const [l, r] = se.useState(!1) + return h.jsx('button', { + className: 'button', + style: { minWidth: 100 }, + onClick: async () => { + const a = s.body + ? s.body + : await fetch(s.path).then((c) => c.text()) + ;(await navigator.clipboard.writeText(ig + a), + r(!0), + setTimeout(() => { + r(!1) + }, 3e3)) + }, + children: l ? 'Copied' : 'Copy prompt', + }) + }, + sg = ({ errorPrefix: s, diff: l, errorSuffix: r }) => { + const a = se.useMemo(() => va(s), [s]), + c = se.useMemo(() => va(r), [r]) + return h.jsxs('div', { + 'data-testid': 'test-screenshot-error-view', + className: 'test-error-view', + children: [ + h.jsx('div', { + dangerouslySetInnerHTML: { __html: a || '' }, + className: 'test-error-text', + style: { marginBottom: 20 }, + }), + h.jsx(q0, { diff: l, hideDetails: !0 }, 'image-diff'), + h.jsx('div', { + 'data-testid': 'error-suffix', + dangerouslySetInnerHTML: { __html: c || '' }, + className: 'test-error-text', + }), + ], + }) + } + function va(s) { + return tg(s || '', { + bg: 'var(--color-canvas-subtle)', + fg: 'var(--color-fg-default)', + }) + } + function og(s, l) { + var a + const r = new Map() + for (const c of s) { + const f = c.name.match( + /^(.*)-(expected|actual|diff|previous)(\.[^.]+)?$/, + ) + if (!f) continue + const [, d, m, g = ''] = f, + w = d + g + let v = r.get(w) + ;(v || ((v = { name: w, anchors: [`attachment-${d}`] }), r.set(w, v)), + v.anchors.push(`attachment-${l.attachments.indexOf(c)}`), + m === 'actual' && (v.actual = { attachment: c }), + m === 'expected' && + (v.expected = { attachment: c, title: 'Expected' }), + m === 'previous' && + (v.expected = { attachment: c, title: 'Previous' }), + m === 'diff' && (v.diff = { attachment: c })) + } + for (const [c, f] of r) + !f.actual || !f.expected + ? r.delete(c) + : (s.delete(f.actual.attachment), + s.delete(f.expected.attachment), + s.delete((a = f.diff) == null ? void 0 : a.attachment)) + return [...r.values()] + } + const ag = ({ test: s, result: l }) => { + const { + screenshots: r, + videos: a, + traces: c, + otherAttachments: f, + diffs: d, + errors: m, + otherAttachmentAnchors: g, + screenshotAnchors: w, + } = se.useMemo(() => { + const v = l.attachments.filter((O) => !O.name.startsWith('_')), + S = new Set(v.filter((O) => O.contentType.startsWith('image/'))), + I = [...S].map((O) => `attachment-${v.indexOf(O)}`), + B = v.filter((O) => O.contentType.startsWith('video/')), + V = v.filter((O) => O.name === 'trace'), + A = new Set(v) + ;[...S, ...B, ...V].forEach((O) => A.delete(O)) + const y = [...A].map((O) => `attachment-${v.indexOf(O)}`), + E = og(S, l), + j = ug(l.errors, E, l.attachments) + return { + screenshots: [...S], + videos: B, + traces: V, + otherAttachments: A, + diffs: E, + errors: j, + otherAttachmentAnchors: y, + screenshotAnchors: I, + } + }, [l]) + return h.jsxs('div', { + className: 'test-result', + children: [ + !!m.length && + h.jsx(Bt, { + header: 'Errors', + children: m.map((v, S) => + v.type === 'screenshot' + ? h.jsx( + sg, + { + errorPrefix: v.errorPrefix, + diff: v.diff, + errorSuffix: v.errorSuffix, + }, + 'test-result-error-message-' + S, + ) + : h.jsx( + _0, + { error: v.error, context: v.context }, + 'test-result-error-message-' + S, + ), + ), + }), + !!l.steps.length && + h.jsx(Bt, { + header: 'Test Steps', + children: l.steps.map((v, S) => + h.jsx( + ep, + { step: v, result: l, test: s, depth: 0 }, + `step-${S}`, + ), + ), + }), + d.map((v, S) => + h.jsx( + vi, + { + id: v.anchors, + children: h.jsx(Bt, { + dataTestId: 'test-results-image-diff', + header: `Image mismatch: ${v.name}`, + revealOnAnchorId: v.anchors, + children: h.jsx(q0, { diff: v }), + }), + }, + `diff-${S}`, + ), + ), + !!r.length && + h.jsx(Bt, { + header: 'Screenshots', + revealOnAnchorId: w, + children: r.map((v, S) => + h.jsxs( + vi, + { + id: `attachment-${l.attachments.indexOf(v)}`, + children: [ + h.jsx('a', { + href: v.path, + children: h.jsx('img', { + className: 'screenshot', + src: v.path, + }), + }), + h.jsx(Ll, { attachment: v, result: l }), + ], + }, + `screenshot-${S}`, + ), + ), + }), + !!c.length && + h.jsx(vi, { + id: 'attachment-trace', + children: h.jsx(Bt, { + header: 'Traces', + revealOnAnchorId: 'attachment-trace', + children: h.jsxs('div', { + children: [ + h.jsx('a', { + href: K0(c), + children: h.jsx('img', { + className: 'screenshot', + src: Jm, + style: { width: 192, height: 117, marginLeft: 20 }, + }), + }), + c.map((v, S) => + h.jsx( + Ll, + { + attachment: v, + result: l, + linkName: + c.length === 1 ? 'trace' : `trace-${S + 1}`, + }, + `trace-${S}`, + ), + ), + ], + }), + }), + }), + !!a.length && + h.jsx(vi, { + id: 'attachment-video', + children: h.jsx(Bt, { + header: 'Videos', + revealOnAnchorId: 'attachment-video', + children: a.map((v) => + h.jsxs( + 'div', + { + children: [ + h.jsx('video', { + controls: !0, + children: h.jsx('source', { + src: v.path, + type: v.contentType, + }), + }), + h.jsx(Ll, { attachment: v, result: l }), + ], + }, + v.path, + ), + ), + }), + }), + !!f.size && + h.jsx(Bt, { + header: 'Attachments', + revealOnAnchorId: g, + dataTestId: 'attachments', + children: [...f].map((v, S) => + h.jsx( + vi, + { + id: `attachment-${l.attachments.indexOf(v)}`, + children: h.jsx(Ll, { + attachment: v, + result: l, + openInNewTab: v.contentType.startsWith('text/html'), + }), + }, + `attachment-link-${S}`, + ), + ), + }), + ], + }) + } + function ug(s, l, r) { + return s.map((a, c) => { + const f = a.split(` +`)[0] + if (f.includes('toHaveScreenshot') || f.includes('toMatchSnapshot')) { + const m = l.find((g) => { + var v + const w = (v = g.actual) == null ? void 0 : v.attachment.name + return w && a.includes(w) + }) + if (m) { + const g = a.split(` +`), + w = g.findIndex((B) => /Expected:|Previous:|Received:/.test(B)), + v = + w !== -1 + ? g.slice(0, w).join(` +`) + : g[0], + S = g.findIndex((B) => / +Diff:/.test(B)), + I = + S !== -1 + ? g.slice(S + 2).join(` +`) + : g.slice(1).join(` +`) + return { + type: 'screenshot', + diff: m, + errorPrefix: v, + errorSuffix: I, + } + } + } + const d = r.find((m) => m.name === `_error-context-${c}`) + return { type: 'regular', error: a, context: d } + }) + } + const ep = ({ test: s, step: l, result: r, depth: a }) => + h.jsx(z0, { + title: h.jsxs('span', { + 'aria-label': l.title, + children: [ + h.jsx('span', { + style: { float: 'right' }, + children: kr(l.duration), + }), + l.attachments.length > 0 && + h.jsx('a', { + style: { float: 'right' }, + title: 'reveal attachment', + href: Zn({ + test: s, + result: r, + anchor: `attachment-${l.attachments[0]}`, + }), + onClick: (c) => { + c.stopPropagation() + }, + children: W0(), + }), + Ei( + l.error || l.duration === -1 + ? 'failed' + : l.skipped + ? 'skipped' + : 'passed', + ), + h.jsx('span', { children: l.title }), + l.count > 1 && + h.jsxs(h.Fragment, { + children: [ + ' ✕ ', + h.jsx('span', { + className: 'test-result-counter', + children: l.count, + }), + ], + }), + l.location && + h.jsxs('span', { + className: 'test-result-path', + children: ['— ', l.location.file, ':', l.location.line], + }), + ], + }), + loadChildren: + l.steps.length || l.snippet + ? () => { + const c = l.snippet + ? [ + h.jsx( + $0, + { testId: 'test-snippet', code: l.snippet }, + 'line', + ), + ] + : [], + f = l.steps.map((d, m) => + h.jsx( + ep, + { step: d, depth: a + 1, result: r, test: s }, + m, + ), + ) + return c.concat(f) + } + : void 0, + depth: a, + }), + cg = ({ projectNames: s, test: l, run: r, next: a, prev: c }) => { + const [f, d] = se.useState(r), + m = se.useContext(Et), + g = m.has('q') ? '&q=' + m.get('q') : '', + w = se.useMemo(() => { + if (l) return l.tags + }, [l]), + v = + (l == null + ? void 0 + : l.annotations.filter((S) => !S.type.startsWith('_'))) ?? [] + return h.jsxs('div', { + className: 'test-case-column vbox', + children: [ + l && + h.jsxs('div', { + className: 'hbox', + children: [ + h.jsx('div', { + className: 'test-case-path', + children: l.path.join(' › '), + }), + h.jsx('div', { style: { flex: 'auto' } }), + h.jsx('div', { + className: Qt(!c && 'hidden'), + children: h.jsx(ht, { + href: Zn({ test: c }) + g, + children: '« previous', + }), + }), + h.jsx('div', { style: { width: 10 } }), + h.jsx('div', { + className: Qt(!a && 'hidden'), + children: h.jsx(ht, { + href: Zn({ test: a }) + g, + children: 'next »', + }), + }), + ], + }), + l && + h.jsx('div', { + className: 'test-case-title', + children: l == null ? void 0 : l.title, + }), + l && + h.jsxs('div', { + className: 'hbox', + children: [ + h.jsx('div', { + className: 'test-case-location', + children: h.jsxs(Oa, { + value: `${l == null ? void 0 : l.location.file}:${l == null ? void 0 : l.location.line}`, + children: [l.location.file, ':', l.location.line], + }), + }), + h.jsx('div', { style: { flex: 'auto' } }), + h.jsx('div', { + className: 'test-case-duration', + children: kr(l.duration), + }), + ], + }), + l && + (!!l.projectName || w) && + h.jsxs('div', { + className: 'test-case-project-labels-row', + children: [ + l && + !!l.projectName && + h.jsx(G0, { + projectNames: s, + projectName: l.projectName, + }), + w && h.jsx(dg, { labels: w }), + ], + }), + (l == null ? void 0 : l.results.length) === 0 && + v.length !== 0 && + h.jsx(Bt, { + header: 'Annotations', + dataTestId: 'test-case-annotations', + children: v.map((S, I) => h.jsx(Bd, { annotation: S }, I)), + }), + l && + h.jsx(Zm, { + tabs: + l.results.map((S, I) => ({ + id: String(I), + title: h.jsxs('div', { + style: { display: 'flex', alignItems: 'center' }, + children: [ + Ei(S.status), + ' ', + fg(I), + l.results.length > 1 && + h.jsx('span', { + className: 'test-case-run-duration', + children: kr(S.duration), + }), + ], + }), + render: () => { + const B = S.annotations.filter( + (V) => !V.type.startsWith('_'), + ) + return h.jsxs(h.Fragment, { + children: [ + !!B.length && + h.jsx(Bt, { + header: 'Annotations', + dataTestId: 'test-case-annotations', + children: B.map((V, A) => + h.jsx(Bd, { annotation: V }, A), + ), + }), + h.jsx(ag, { test: l, result: S }), + ], + }) + }, + })) || [], + selectedTab: String(f), + setSelectedTab: (S) => d(+S), + }), + ], + }) + } + function Bd({ annotation: { type: s, description: l } }) { + return h.jsxs('div', { + className: 'test-case-annotation', + children: [ + h.jsx('span', { style: { fontWeight: 'bold' }, children: s }), + l && h.jsxs(Oa, { value: l, children: [': ', Zl(l)] }), + ], + }) + } + function fg(s) { + return s ? `Retry #${s}` : 'Run' + } + const dg = ({ labels: s }) => + s.length > 0 + ? h.jsx(h.Fragment, { + children: s.map((l) => + h.jsx( + 'a', + { + style: { + textDecoration: 'none', + color: 'var(--color-fg-default)', + }, + href: `#?q=${l}`, + children: h.jsx('span', { + style: { margin: '6px 0 0 6px', cursor: 'pointer' }, + className: Qt('label', 'label-color-' + J0(l)), + children: l.slice(1), + }), + }, + l, + ), + ), + }) + : null, + pg = ({ + file: s, + projectNames: l, + isFileExpanded: r, + setFileExpanded: a, + }) => { + const c = se.useContext(Et), + f = c.has('q') ? '&q=' + c.get('q') : '' + return h.jsx(Z0, { + expanded: r(s.fileId), + noInsets: !0, + setExpanded: (d) => a(s.fileId, d), + header: h.jsx('span', { children: s.fileName }), + children: s.tests.map((d) => + h.jsxs( + 'div', + { + className: Qt( + 'test-file-test', + 'test-file-test-outcome-' + d.outcome, + ), + children: [ + h.jsxs('div', { + className: 'hbox', + style: { alignItems: 'flex-start' }, + children: [ + h.jsxs('div', { + className: 'hbox', + children: [ + h.jsx('span', { + className: 'test-file-test-status-icon', + children: Ei(d.outcome), + }), + h.jsxs('span', { + children: [ + h.jsx(ht, { + href: Zn({ test: d }) + f, + title: [...d.path, d.title].join(' › '), + children: h.jsx('span', { + className: 'test-file-title', + children: [...d.path, d.title].join(' › '), + }), + }), + l.length > 1 && + !!d.projectName && + h.jsx(G0, { + projectNames: l, + projectName: d.projectName, + }), + h.jsx(vg, { labels: d.tags }), + ], + }), + ], + }), + h.jsx('span', { + 'data-testid': 'test-duration', + style: { minWidth: '50px', textAlign: 'right' }, + children: kr(d.duration), + }), + ], + }), + h.jsxs('div', { + className: 'test-file-details-row', + children: [ + h.jsx(ht, { + href: Zn({ test: d }), + title: [...d.path, d.title].join(' › '), + className: 'test-file-path-link', + children: h.jsxs('span', { + className: 'test-file-path', + children: [d.location.file, ':', d.location.line], + }), + }), + hg(d), + mg(d), + gg(d), + ], + }), + ], + }, + `test-${d.testId}`, + ), + ), + }) + } + function hg(s) { + for (const l of s.results) + for (const r of l.attachments) + if ( + r.contentType.startsWith('image/') && + r.name.match(/-(expected|actual|diff)/) + ) + return h.jsx(ht, { + href: Zn({ + test: s, + result: l, + anchor: `attachment-${l.attachments.indexOf(r)}`, + }), + title: 'View images', + className: 'test-file-badge', + children: Bm(), + }) + } + function mg(s) { + const l = s.results.find((r) => + r.attachments.some((a) => a.name === 'video'), + ) + return l + ? h.jsx(ht, { + href: Zn({ test: s, result: l, anchor: 'attachment-video' }), + title: 'View video', + className: 'test-file-badge', + children: Hm(), + }) + : void 0 + } + function gg(s) { + const l = s.results + .map((r) => r.attachments.filter((a) => a.name === 'trace')) + .filter((r) => r.length > 0)[0] + if (l) + return h.jsxs(ht, { + href: K0(l), + title: 'View Trace', + className: 'button test-file-badge', + children: [Fm(), h.jsx('span', { children: 'View Trace' })], + }) + } + const vg = ({ labels: s }) => { + const l = se.useContext(Et), + r = (a, c) => { + var m + a.preventDefault() + const d = ( + ((m = l.get('q')) == null ? void 0 : m.toString()) || '' + ).split(' ') + Da(Zt(d, c, a.metaKey || a.ctrlKey)) + } + return s.length > 0 + ? h.jsx(h.Fragment, { + children: s.map((a) => + h.jsx( + 'span', + { + style: { margin: '6px 0 0 6px', cursor: 'pointer' }, + className: Qt('label', 'label-color-' + J0(a)), + onClick: (c) => r(c, a), + children: a.slice(1), + }, + a, + ), + ), + }) + : null + } + class yg extends se.Component { + constructor() { + super(...arguments) + Gt(this, 'state', { error: null, errorInfo: null }) + } + componentDidCatch(r, a) { + this.setState({ error: r, errorInfo: a }) + } + render() { + var r, a, c + return this.state.error || this.state.errorInfo + ? h.jsxs('div', { + className: 'metadata-view p-3', + children: [ + h.jsx('p', { + children: + 'An error was encountered when trying to render metadata.', + }), + h.jsx('p', { + children: h.jsxs('pre', { + style: { overflow: 'scroll' }, + children: [ + (r = this.state.error) == null ? void 0 : r.message, + h.jsx('br', {}), + (a = this.state.error) == null ? void 0 : a.stack, + h.jsx('br', {}), + (c = this.state.errorInfo) == null + ? void 0 + : c.componentStack, + ], + }), + }), + ], + }) + : this.props.children + } + } + const xg = (s) => + h.jsx(yg, { children: h.jsx(wg, { metadata: s.metadata }) }), + wg = (s) => { + const l = se.useContext(Et), + r = s.metadata, + a = l.has('show-metadata-other') + ? Object.entries(s.metadata).filter(([f]) => !tp.has(f)) + : [] + if (r.ci || r.gitCommit || a.length > 0) + return h.jsxs('div', { + className: 'metadata-view', + children: [ + r.ci && !r.gitCommit && h.jsx(Ag, { info: r.ci }), + r.gitCommit && h.jsx(Eg, { ci: r.ci, commit: r.gitCommit }), + a.length > 0 && + (r.gitCommit || r.ci) && + h.jsx('div', { className: 'metadata-separator' }), + h.jsx('div', { + className: 'metadata-section metadata-properties', + role: 'list', + children: a.map(([f, d]) => { + const m = + typeof d != 'object' || d === null || d === void 0 + ? String(d) + : JSON.stringify(d), + g = m.length > 1e3 ? m.slice(0, 1e3) + '…' : m + return h.jsx( + 'div', + { + className: 'copyable-property', + role: 'listitem', + children: h.jsxs(Oa, { + value: m, + children: [ + h.jsx('span', { + style: { fontWeight: 'bold' }, + title: f, + children: f, + }), + ': ', + h.jsx('span', { title: g, children: Zl(g) }), + ], + }), + }, + f, + ) + }), + }), + ], + }) + }, + Ag = ({ info: s }) => { + const l = s.prTitle || `Commit ${s.commitHash}`, + r = s.prHref || s.commitHref + return h.jsx('div', { + className: 'metadata-section', + role: 'list', + children: h.jsx('div', { + role: 'listitem', + children: h.jsx('a', { + href: r, + target: '_blank', + rel: 'noopener noreferrer', + title: l, + children: l, + }), + }), + }) + }, + Eg = ({ ci: s, commit: l }) => { + const r = (s == null ? void 0 : s.prTitle) || l.subject, + a = + (s == null ? void 0 : s.prHref) || + (s == null ? void 0 : s.commitHref), + c = ` <${l.author.email}>`, + f = `${l.author.name}${c}`, + d = Intl.DateTimeFormat(void 0, { dateStyle: 'medium' }).format( + l.committer.time, + ), + m = Intl.DateTimeFormat(void 0, { + dateStyle: 'full', + timeStyle: 'long', + }).format(l.committer.time) + return h.jsxs('div', { + className: 'metadata-section', + role: 'list', + children: [ + h.jsxs('div', { + role: 'listitem', + children: [ + a && + h.jsx('a', { + href: a, + target: '_blank', + rel: 'noopener noreferrer', + title: r, + children: r, + }), + !a && h.jsx('span', { title: r, children: r }), + ], + }), + h.jsxs('div', { + role: 'listitem', + className: 'hbox', + children: [ + h.jsx('span', { className: 'mr-1', children: f }), + h.jsxs('span', { title: m, children: [' on ', d] }), + ], + }), + ], + }) + }, + tp = new Set(['ci', 'gitCommit', 'gitDiff', 'actualWorkers']), + Cg = (s) => { + const l = Object.entries(s).filter(([r]) => !tp.has(r)) + return !s.ci && !s.gitCommit && !l.length + }, + Sg = ({ + tests: s, + expandedFiles: l, + setExpandedFiles: r, + projectNames: a, + }) => { + const c = se.useMemo(() => { + const f = [] + let d = 0 + for (const m of s) + ((d += m.tests.length), + f.push({ file: m, defaultExpanded: d < 200 })) + return f + }, [s]) + return h.jsx(h.Fragment, { + children: c.map(({ file: f, defaultExpanded: d }) => + h.jsx( + pg, + { + file: f, + projectNames: a, + isFileExpanded: (m) => { + const g = l.get(m) + return g === void 0 ? d : !!g + }, + setFileExpanded: (m, g) => { + const w = new Map(l) + ;(w.set(m, g), r(w)) + }, + }, + `file-${f.fileId}`, + ), + ), + }) + }, + kg = ({ + report: s, + filteredStats: l, + metadataVisible: r, + toggleMetadataVisible: a, + }) => + s + ? h.jsxs(h.Fragment, { + children: [ + h.jsxs('div', { + className: 'mx-1', + style: { display: 'flex', marginTop: 10 }, + children: [ + h.jsxs('div', { + className: 'test-file-header-info', + children: [ + !Cg(s.metadata) && + h.jsxs('div', { + className: 'metadata-toggle', + role: 'button', + onClick: a, + title: r ? 'Hide metadata' : 'Show metadata', + children: [r ? Pa() : Kl(), 'Metadata'], + }), + s.projectNames.length === 1 && + !!s.projectNames[0] && + h.jsxs('div', { + 'data-testid': 'project-name', + children: ['Project: ', s.projectNames[0]], + }), + l && + h.jsxs('div', { + 'data-testid': 'filtered-tests-count', + children: [ + 'Filtered: ', + l.total, + ' ', + !!l.total && '(' + kr(l.duration) + ')', + ], + }), + ], + }), + h.jsx('div', { style: { flex: 'auto' } }), + h.jsx('div', { + 'data-testid': 'overall-time', + style: { + color: 'var(--color-fg-subtle)', + marginRight: '10px', + }, + children: s + ? new Date(s.startTime).toLocaleString() + : '', + }), + h.jsxs('div', { + 'data-testid': 'overall-duration', + style: { color: 'var(--color-fg-subtle)' }, + children: ['Total time: ', kr(s.duration ?? 0)], + }), + ], + }), + r && h.jsx(xg, { metadata: s.metadata }), + !!s.errors.length && + h.jsx(Bt, { + header: 'Errors', + dataTestId: 'report-errors', + children: s.errors.map((c, f) => + h.jsx( + _0, + { error: c }, + 'test-report-error-message-' + f, + ), + ), + }), + ], + }) + : null, + Ig = (s) => !s.has('testId'), + Rg = (s) => s.has('testId'), + Tg = ({ report: s }) => { + const l = se.useContext(Et), + [r, a] = se.useState(new Map()), + [c, f] = se.useState(l.get('q') || ''), + [d, m] = se.useState(!1), + g = se.useMemo(() => { + const I = new Map() + for (const B of (s == null ? void 0 : s.json().files) || []) + for (const V of B.tests) I.set(V.testId, B.fileId) + return I + }, [s]), + w = se.useMemo(() => Gl.parse(c), [c]), + v = se.useMemo( + () => + w.empty() + ? void 0 + : Pg((s == null ? void 0 : s.json().files) || [], w), + [s, w], + ), + S = se.useMemo(() => { + const I = { files: [], tests: [] } + for (const B of (s == null ? void 0 : s.json().files) || []) { + const V = B.tests.filter((A) => w.matches(A)) + ;(V.length && I.files.push({ ...B, tests: V }), + I.tests.push(...V)) + } + return I + }, [s, w]) + return h.jsx('div', { + className: 'htmlreport vbox px-4 pb-4', + children: h.jsxs('main', { + children: [ + (s == null ? void 0 : s.json()) && + h.jsx(Gm, { + stats: s.json().stats, + filterText: c, + setFilterText: f, + }), + h.jsxs(Dd, { + predicate: Ig, + children: [ + h.jsx(kg, { + report: s == null ? void 0 : s.json(), + filteredStats: v, + metadataVisible: d, + toggleMetadataVisible: () => m((I) => !I), + }), + h.jsx(Sg, { + tests: S.files, + expandedFiles: r, + setExpandedFiles: a, + projectNames: + (s == null ? void 0 : s.json().projectNames) || [], + }), + ], + }), + h.jsx(Dd, { + predicate: Rg, + children: + !!s && + h.jsx(jg, { + report: s, + tests: S.tests, + testIdToFileIdMap: g, + }), + }), + ], + }), + }) + }, + jg = ({ report: s, testIdToFileIdMap: l, tests: r }) => { + const a = se.useContext(Et), + [c, f] = se.useState(), + d = a.get('testId'), + m = +(a.get('run') || '0'), + { prev: g, next: w } = se.useMemo(() => { + const v = r.findIndex((B) => B.testId === d), + S = v > 0 ? r[v - 1] : void 0, + I = v < r.length - 1 ? r[v + 1] : void 0 + return { prev: S, next: I } + }, [d, r]) + return ( + se.useEffect(() => { + ;(async () => { + if (!d || d === (c == null ? void 0 : c.testId)) return + const v = l.get(d) + if (!v) return + const S = await s.entry(`${v}.json`) + for (const I of S.tests) + if (I.testId === d) { + f(I) + break + } + })() + }, [c, s, d, l]), + h.jsx(cg, { + projectNames: s.json().projectNames, + next: w, + prev: g, + test: c, + run: m, + }) + ) + } + function Pg(s, l) { + const r = { total: 0, duration: 0 } + for (const a of s) { + const c = a.tests.filter((f) => l.matches(f)) + r.total += c.length + for (const f of c) r.duration += f.duration + } + return r + } + const Og = + "data:image/svg+xml,%3csvg%20width='400'%20height='400'%20viewBox='0%200%20400%20400'%20fill='none'%20xmlns='http://www.w3.org/2000/svg'%3e%3cpath%20d='M136.444%20221.556C123.558%20225.213%20115.104%20231.625%20109.535%20238.032C114.869%20233.364%20122.014%20229.08%20131.652%20226.348C141.51%20223.554%20149.92%20223.574%20156.869%20224.915V219.481C150.941%20218.939%20144.145%20219.371%20136.444%20221.556ZM108.946%20175.876L61.0895%20188.484C61.0895%20188.484%2061.9617%20189.716%2063.5767%20191.36L104.153%20180.668C104.153%20180.668%20103.578%20188.077%2098.5847%20194.705C108.03%20187.559%20108.946%20175.876%20108.946%20175.876ZM149.005%20288.347C81.6582%20306.486%2046.0272%20228.438%2035.2396%20187.928C30.2556%20169.229%2028.0799%20155.067%2027.5%20145.928C27.4377%20144.979%2027.4665%20144.179%2027.5336%20143.446C24.04%20143.657%2022.3674%20145.473%2022.7077%20150.721C23.2876%20159.855%2025.4633%20174.016%2030.4473%20192.721C41.2301%20233.225%2076.8659%20311.273%20144.213%20293.134C158.872%20289.185%20169.885%20281.992%20178.152%20272.81C170.532%20279.692%20160.995%20285.112%20149.005%20288.347ZM161.661%20128.11V132.903H188.077C187.535%20131.206%20186.989%20129.677%20186.447%20128.11H161.661Z'%20fill='%232D4552'/%3e%3cpath%20d='M193.981%20167.584C205.861%20170.958%20212.144%20179.287%20215.465%20186.658L228.711%20190.42C228.711%20190.42%20226.904%20164.623%20203.57%20157.995C181.741%20151.793%20168.308%20170.124%20166.674%20172.496C173.024%20167.972%20182.297%20164.268%20193.981%20167.584ZM299.422%20186.777C277.573%20180.547%20264.145%20198.916%20262.535%20201.255C268.89%20196.736%20278.158%20193.031%20289.837%20196.362C301.698%20199.741%20307.976%20208.06%20311.307%20215.436L324.572%20219.212C324.572%20219.212%20322.736%20193.41%20299.422%20186.777ZM286.262%20254.795L176.072%20223.99C176.072%20223.99%20177.265%20230.038%20181.842%20237.869L274.617%20263.805C282.255%20259.386%20286.262%20254.795%20286.262%20254.795ZM209.867%20321.102C122.618%20297.71%20133.166%20186.543%20147.284%20133.865C153.097%20112.156%20159.073%2096.0203%20164.029%2085.204C161.072%2084.5953%20158.623%2086.1529%20156.203%2091.0746C150.941%20101.747%20144.212%20119.124%20137.7%20143.45C123.586%20196.127%20113.038%20307.29%20200.283%20330.682C241.406%20341.699%20273.442%20324.955%20297.323%20298.659C274.655%20319.19%20245.714%20330.701%20209.867%20321.102Z'%20fill='%232D4552'/%3e%3cpath%20d='M161.661%20262.296V239.863L99.3324%20257.537C99.3324%20257.537%20103.938%20230.777%20136.444%20221.556C146.302%20218.762%20154.713%20218.781%20161.661%20220.123V128.11H192.869C189.471%20117.61%20186.184%20109.526%20183.423%20103.909C178.856%2094.612%20174.174%20100.775%20163.545%20109.665C156.059%20115.919%20137.139%20129.261%20108.668%20136.933C80.1966%20144.61%2057.179%20142.574%2047.5752%20140.911C33.9601%20138.562%2026.8387%20135.572%2027.5049%20145.928C28.0847%20155.062%2030.2605%20169.224%2035.2445%20187.928C46.0272%20228.433%2081.663%20306.481%20149.01%20288.342C166.602%20283.602%20179.019%20274.233%20187.626%20262.291H161.661V262.296ZM61.0848%20188.484L108.946%20175.876C108.946%20175.876%20107.551%20194.288%2089.6087%20199.018C71.6614%20203.743%2061.0848%20188.484%2061.0848%20188.484Z'%20fill='%23E2574C'/%3e%3cpath%20d='M341.786%20129.174C329.345%20131.355%20299.498%20134.072%20262.612%20124.185C225.716%20114.304%20201.236%2097.0224%20191.537%2088.8994C177.788%2077.3834%20171.74%2069.3802%20165.788%2081.4857C160.526%2092.163%20153.797%20109.54%20147.284%20133.866C133.171%20186.543%20122.623%20297.706%20209.867%20321.098C297.093%20344.47%20343.53%20242.92%20357.644%20190.238C364.157%20165.917%20367.013%20147.5%20367.799%20135.625C368.695%20122.173%20359.455%20126.078%20341.786%20129.174ZM166.497%20172.756C166.497%20172.756%20180.246%20151.372%20203.565%20158C226.899%20164.628%20228.706%20190.425%20228.706%20190.425L166.497%20172.756ZM223.42%20268.713C182.403%20256.698%20176.077%20223.99%20176.077%20223.99L286.262%20254.796C286.262%20254.791%20264.021%20280.578%20223.42%20268.713ZM262.377%20201.495C262.377%20201.495%20276.107%20180.126%20299.422%20186.773C322.736%20193.411%20324.572%20219.208%20324.572%20219.208L262.377%20201.495Z'%20fill='%232EAD33'/%3e%3cpath%20d='M139.88%20246.04L99.3324%20257.532C99.3324%20257.532%20103.737%20232.44%20133.607%20222.496L110.647%20136.33L108.663%20136.933C80.1918%20144.611%2057.1742%20142.574%2047.5704%20140.911C33.9554%20138.563%2026.834%20135.572%2027.5001%20145.929C28.08%20155.063%2030.2557%20169.224%2035.2397%20187.929C46.0225%20228.433%2081.6583%20306.481%20149.005%20288.342L150.989%20287.719L139.88%20246.04ZM61.0848%20188.485L108.946%20175.876C108.946%20175.876%20107.551%20194.288%2089.6087%20199.018C71.6615%20203.743%2061.0848%20188.485%2061.0848%20188.485Z'%20fill='%23D65348'/%3e%3cpath%20d='M225.27%20269.163L223.415%20268.712C182.398%20256.698%20176.072%20223.99%20176.072%20223.99L232.89%20239.872L262.971%20124.281L262.607%20124.185C225.711%20114.304%20201.232%2097.0224%20191.532%2088.8994C177.783%2077.3834%20171.735%2069.3802%20165.783%2081.4857C160.526%2092.163%20153.797%20109.54%20147.284%20133.866C133.171%20186.543%20122.623%20297.706%20209.867%20321.097L211.655%20321.5L225.27%20269.163ZM166.497%20172.756C166.497%20172.756%20180.246%20151.372%20203.565%20158C226.899%20164.628%20228.706%20190.425%20228.706%20190.425L166.497%20172.756Z'%20fill='%231D8D22'/%3e%3cpath%20d='M141.946%20245.451L131.072%20248.537C133.641%20263.019%20138.169%20276.917%20145.276%20289.195C146.513%20288.922%20147.74%20288.687%20149%20288.342C152.302%20287.451%20155.364%20286.348%20158.312%20285.145C150.371%20273.361%20145.118%20259.789%20141.946%20245.451ZM137.7%20143.451C132.112%20164.307%20127.113%20194.326%20128.489%20224.436C130.952%20223.367%20133.554%20222.371%20136.444%20221.551L138.457%20221.101C136.003%20188.939%20141.308%20156.165%20147.284%20133.866C148.799%20128.225%20150.318%20122.978%20151.832%20118.085C149.393%20119.637%20146.767%20121.228%20143.776%20122.867C141.759%20129.093%20139.722%20135.898%20137.7%20143.451Z'%20fill='%23C04B41'/%3e%3c/svg%3e", + la = Sm, + Ma = document.createElement('link') + Ma.rel = 'shortcut icon' + Ma.href = Og + document.head.appendChild(Ma) + const Dg = () => { + const [s, l] = se.useState() + return ( + se.useEffect(() => { + if (s) return + const r = new Ng() + r.load().then(() => l(r)) + }, [s]), + h.jsx(bm, { children: h.jsx(Tg, { report: s }) }) + ) + } + window.onload = () => { + Pm.createRoot(document.querySelector('#root')).render(h.jsx(Dg, {})) + } + const Hd = 'playwrightReportStorageForHMR' + class Ng { + constructor() { + Gt(this, '_entries', new Map()) + Gt(this, '_json') + } + async load() { + const l = await new Promise((a) => { + if (window.playwrightReportBase64) + return a(window.playwrightReportBase64) + if (window.opener) + (window.addEventListener( + 'message', + (c) => { + c.source === window.opener && + (localStorage.setItem(Hd, c.data), a(c.data)) + }, + { once: !0 }, + ), + window.opener.postMessage('ready', '*')) + else { + const c = localStorage.getItem(Hd) + if (c) return a(c) + alert('couldnt find report, something with HMR is broken') + } + }), + r = new la.ZipReader(new la.Data64URIReader(l), { + useWebWorkers: !1, + }) + for (const a of await r.getEntries()) this._entries.set(a.filename, a) + this._json = await this.entry('report.json') + } + json() { + return this._json + } + async entry(l) { + const r = this._entries.get(l), + a = new la.TextWriter() + return (await r.getData(a), JSON.parse(await a.getData())) + } + } + + -
    +
    \ No newline at end of file + window.playwrightReportBase64 = + 'data:application/zip;base64,UEsDBBQAAAgIABu4PVtszRUijQQAAAwZAAAZAAAAYzMxZmYxNDRkYzRmZWUzYWNkMGEuanNvbu1YbW/bNhD+K5y+2AZsS6RebAlYgDUYsAFDERQpCqzOBoqiHM0SqUlUk8DJf++RVhZHdlzH8bKuqP1BMnl8eLzjvTxeWmmW818TK7KYi9MUe17CvJRzl7LEodbQzL+lBQcJWpbjuuRsrGqYULyGZ/Rxad6ehBgFbjwNqetOYz4JvanHvTjWyzOVa9C39FM2pyoTc6QkKmWtYLKs5F+cqXZfdlnJImsKmMglA1kprGhpNNvQKs8EDLpDi8m8KUAO3w2tpKnaVdgjQ4sKIZUZ0PpfgC503r7JRjFpNm0EvwZUxROtD1WXK4GK103enrsDWytaqfPMrCYO8UdOOCLhOcGR40S+P3b96e+WRlDVjRU5egEvWwu2xnjDU1lx9IuUC32YLyIGjkZ80IN4wTbYNLtWTcUjFFfyqubVXtDuY2hM/G3QLeL5TcnHOW0Eu9wL3OuCew/gYGWqFGWXBReqHWCyEQrkQGqRlSU4JUppXvO7ZwkPt5iESaH4tdpDa28aPtZ6l0HGgl+dHgX6dc1R0jnfR+Gw60FMdlijtYQ2ytm+G/jdDfBr2ORQA2q7jedSyb492ON4gTPpRO7uw+2Z97y1vOdB4uNVJSuQ/Vk/V841SkborIIHyCIjgvraLWOxysV8EKFTkyTR/YjOzZn4RPMsQe/f/TYTpzTPUS7n0UzMGsfB8UdSIDS6X9Cm85llz6whuqKZGQEzZjkM5pImM+t+HSlmwnrayvBb6N8wZyGEXHSLdMHp9zYrR2+IaH0jGOovzVnR3QD9eIKWMwELPViIENW6PBii37N7AzONzPTa5w8z7KNba93PP6WKV3sn6AB3E/TWKHlu9G3AOgeGxssS4tHUOFTnD7JagDdOc05FU+6jsUsea+zinf7Yv17uRP5X05UJYC339Ue5/iJE0K1+HBbIJ1+M421h7K+2DDaWcvXm5p3Meb8HCXQB2y7hbAV4vncGatQ92HjM8owt+gZ98gyAGuyAaKNQShmHpq7iJX+Mt2ZSAFXIfg93rbZpUmTCBnFZ24oKuHlsYVfQmfLK5oTbtQT/jMyFtGNaZ2y0Gvm74dWNbdpye604RB7UggcvWBfmMqum1hedQi3RDe5GS/z4Ci4tsWrF/zQXadTmiJFj8ja8C6U7QBDQw3ZBq0Uir8Q/nbOVUEVtH7MQGAKZuI43IQwT7FGX+sx3yZTFAU8xpwz7eFwk1t2FvttysR71O2lG4mHqALlIp2GKceByPw6epBkUwXFHKURVgoxlj8A5dH/yNZIO99ikw+90ZsTfCnsI6VgxpLUjuluhDyMdftglHeH/gXR0TLKV4B2HdPxnHOxw0rG1fL+AdOza4BsgHUGnRzkK6dDM7xtnHRg/0axsFJJdFASTQygIdl9GQZxOlBN3Z7b+TkFemYLgY/1ltxP5OwVZpyDYWRGCY8T1yQvi2jzXCc2q/et3ucUlpwlo1hsMxkrqukYzcQ4R0u994LnuHSEdFPyH1X4Y2A6o92r8ApOvhWBMSEjc2PPCgOKYszR0Auh/GfehsE8xmSQunUziKdlGMC7uPgNQSwMEFAAACAgAG7g9W3n+7BnUAQAAlAQAAAsAAAByZXBvcnQuanNvbt1TTY+bMBD9K5HPJIux+fwHvexppR6qqBrscUIBG5mh3VWU/16b0DRSteplTwuXYWb85r15+MJGJNBAwJoLA0ULDF+d79HPrMmuCZsJPL10I7KGl3nNy7rIZVWnCdOLB+qcZU1Z8UOe8vTPwxNmugEDwrfLGn3RrGFKcGO4lFpJgyhA6RTYrfMZIj6DaTrME6oDzaFAONMNIkbvQuwL0VY1CFG1WNaykijbNh7vaIigz/CzOwWi9rQjt5vcTKE4efcDFW1z1dm7sVvGUBic2kTdmP/DauhsSIqEKTcsY+jj18dVcJklDKx1tCYi/2PgAqctcgsptw5dLL4GVEId+QCdt4aeNQaGGRPmcV6GbQVABOo8ot2+7Y35d/Te+b1ylvCV9imLvEJs6eVtig0x/TSC77X7Ze+DWDT8KeeqDgvNSpHKMlM84xIE5CoXWaXaAg1HUDznh1Gz6zG8yf+s0JJDGgwwVW04LwTmbfGuFbALW9obt1i982Ev+AG+cP4ZjCmzOhOtlHUBvEVl6rQQuVCYy/B/86zUAsqyrbK7Mcf1nkYGwaGgcAh3N2F3GU24rQ+qYs0M0L+thbnvpmlrumu8RsgHM6K2v3Z8/LhwOu5r9eL6G1BLAQI/AxQAAAgIABu4PVtszRUijQQAAAwZAAAZAAAAAAAAAAAAAAC0gQAAAABjMzFmZjE0NGRjNGZlZTNhY2QwYS5qc29uUEsBAj8DFAAACAgAG7g9W3n+7BnUAQAAlAQAAAsAAAAAAAAAAAAAALSBxAQAAHJlcG9ydC5qc29uUEsFBgAAAAACAAIAgAAAAMEGAAAAAA==' + diff --git a/e2e/solid-start/basic-solid-query/playwright.config.ts b/e2e/solid-start/basic-solid-query/playwright.config.ts index 7e0487c881..84636ab0f9 100644 --- a/e2e/solid-start/basic-solid-query/playwright.config.ts +++ b/e2e/solid-start/basic-solid-query/playwright.config.ts @@ -36,4 +36,4 @@ export default defineConfig({ use: { ...devices['Desktop Chrome'] }, }, ], -}) \ No newline at end of file +}) diff --git a/e2e/solid-start/basic-solid-query/postcss.config.mjs b/e2e/solid-start/basic-solid-query/postcss.config.mjs index e99ebc2c0e..2e7af2b7f1 100644 --- a/e2e/solid-start/basic-solid-query/postcss.config.mjs +++ b/e2e/solid-start/basic-solid-query/postcss.config.mjs @@ -3,4 +3,4 @@ export default { tailwindcss: {}, autoprefixer: {}, }, -} \ No newline at end of file +} diff --git a/e2e/solid-start/basic-solid-query/src/components/DefaultCatchBoundary.tsx b/e2e/solid-start/basic-solid-query/src/components/DefaultCatchBoundary.tsx index 92058c37f8..02f53708c9 100644 --- a/e2e/solid-start/basic-solid-query/src/components/DefaultCatchBoundary.tsx +++ b/e2e/solid-start/basic-solid-query/src/components/DefaultCatchBoundary.tsx @@ -5,4 +5,4 @@ import { export function DefaultCatchBoundary(props: ErrorComponentProps) { return -} \ No newline at end of file +} diff --git a/e2e/solid-start/basic-solid-query/src/components/NotFound.tsx b/e2e/solid-start/basic-solid-query/src/components/NotFound.tsx index 4040aa7fcd..8ca552b501 100644 --- a/e2e/solid-start/basic-solid-query/src/components/NotFound.tsx +++ b/e2e/solid-start/basic-solid-query/src/components/NotFound.tsx @@ -4,7 +4,9 @@ import type { JSX } from 'solid-js' export function NotFound(props?: { children?: JSX.Element }) { return (
    -
    {props?.children || 'The page you are looking for does not exist.'}
    +
    + {props?.children || 'The page you are looking for does not exist.'} +

    ) -} \ No newline at end of file +} diff --git a/e2e/solid-start/basic-solid-query/src/routeTree.gen.ts b/e2e/solid-start/basic-solid-query/src/routeTree.gen.ts index 5f2844e46d..b7444e1e0c 100644 --- a/e2e/solid-start/basic-solid-query/src/routeTree.gen.ts +++ b/e2e/solid-start/basic-solid-query/src/routeTree.gen.ts @@ -17,6 +17,9 @@ import { Route as UsersIndexRouteImport } from './routes/users.index' import { Route as PostsIndexRouteImport } from './routes/posts.index' import { Route as UsersUserIdRouteImport } from './routes/users.$userId' import { Route as PostsPostIdRouteImport } from './routes/posts.$postId' +import { Route as ApiUsersRouteImport } from './routes/api.users' +import { Route as PostsPostIdDeepRouteImport } from './routes/posts_.$postId.deep' +import { Route as ApiUsersIdRouteImport } from './routes/api/users.$id' const UsersRoute = UsersRouteImport.update({ id: '/users', @@ -58,24 +61,45 @@ const PostsPostIdRoute = PostsPostIdRouteImport.update({ path: '/$postId', getParentRoute: () => PostsRoute, } as any) +const ApiUsersRoute = ApiUsersRouteImport.update({ + id: '/api/users', + path: '/api/users', + getParentRoute: () => rootRouteImport, +} as any) +const PostsPostIdDeepRoute = PostsPostIdDeepRouteImport.update({ + id: '/posts_/$postId/deep', + path: '/posts/$postId/deep', + getParentRoute: () => rootRouteImport, +} as any) +const ApiUsersIdRoute = ApiUsersIdRouteImport.update({ + id: '/$id', + path: '/$id', + getParentRoute: () => ApiUsersRoute, +} as any) export interface FileRoutesByFullPath { '/': typeof IndexRoute '/deferred': typeof DeferredRoute '/posts': typeof PostsRouteWithChildren '/users': typeof UsersRouteWithChildren + '/api/users': typeof ApiUsersRouteWithChildren '/posts/$postId': typeof PostsPostIdRoute '/users/$userId': typeof UsersUserIdRoute '/posts/': typeof PostsIndexRoute '/users/': typeof UsersIndexRoute + '/api/users/$id': typeof ApiUsersIdRoute + '/posts/$postId/deep': typeof PostsPostIdDeepRoute } export interface FileRoutesByTo { '/': typeof IndexRoute '/deferred': typeof DeferredRoute + '/api/users': typeof ApiUsersRouteWithChildren '/posts/$postId': typeof PostsPostIdRoute '/users/$userId': typeof UsersUserIdRoute '/posts': typeof PostsIndexRoute '/users': typeof UsersIndexRoute + '/api/users/$id': typeof ApiUsersIdRoute + '/posts/$postId/deep': typeof PostsPostIdDeepRoute } export interface FileRoutesById { __root__: typeof rootRouteImport @@ -83,10 +107,13 @@ export interface FileRoutesById { '/deferred': typeof DeferredRoute '/posts': typeof PostsRouteWithChildren '/users': typeof UsersRouteWithChildren + '/api/users': typeof ApiUsersRouteWithChildren '/posts/$postId': typeof PostsPostIdRoute '/users/$userId': typeof UsersUserIdRoute '/posts/': typeof PostsIndexRoute '/users/': typeof UsersIndexRoute + '/api/users/$id': typeof ApiUsersIdRoute + '/posts_/$postId/deep': typeof PostsPostIdDeepRoute } export interface FileRouteTypes { fileRoutesByFullPath: FileRoutesByFullPath @@ -95,28 +122,37 @@ export interface FileRouteTypes { | '/deferred' | '/posts' | '/users' + | '/api/users' | '/posts/$postId' | '/users/$userId' | '/posts/' | '/users/' + | '/api/users/$id' + | '/posts/$postId/deep' fileRoutesByTo: FileRoutesByTo to: | '/' | '/deferred' + | '/api/users' | '/posts/$postId' | '/users/$userId' | '/posts' | '/users' + | '/api/users/$id' + | '/posts/$postId/deep' id: | '__root__' | '/' | '/deferred' | '/posts' | '/users' + | '/api/users' | '/posts/$postId' | '/users/$userId' | '/posts/' | '/users/' + | '/api/users/$id' + | '/posts_/$postId/deep' fileRoutesById: FileRoutesById } export interface RootRouteChildren { @@ -124,6 +160,8 @@ export interface RootRouteChildren { DeferredRoute: typeof DeferredRoute PostsRoute: typeof PostsRouteWithChildren UsersRoute: typeof UsersRouteWithChildren + ApiUsersRoute: typeof ApiUsersRouteWithChildren + PostsPostIdDeepRoute: typeof PostsPostIdDeepRoute } declare module '@tanstack/solid-router' { @@ -184,6 +222,27 @@ declare module '@tanstack/solid-router' { preLoaderRoute: typeof PostsPostIdRouteImport parentRoute: typeof PostsRoute } + '/api/users': { + id: '/api/users' + path: '/api/users' + fullPath: '/api/users' + preLoaderRoute: typeof ApiUsersRouteImport + parentRoute: typeof rootRouteImport + } + '/posts_/$postId/deep': { + id: '/posts_/$postId/deep' + path: '/posts/$postId/deep' + fullPath: '/posts/$postId/deep' + preLoaderRoute: typeof PostsPostIdDeepRouteImport + parentRoute: typeof rootRouteImport + } + '/api/users/$id': { + id: '/api/users/$id' + path: '/$id' + fullPath: '/api/users/$id' + preLoaderRoute: typeof ApiUsersIdRouteImport + parentRoute: typeof ApiUsersRoute + } } } @@ -211,11 +270,25 @@ const UsersRouteChildren: UsersRouteChildren = { const UsersRouteWithChildren = UsersRoute._addFileChildren(UsersRouteChildren) +interface ApiUsersRouteChildren { + ApiUsersIdRoute: typeof ApiUsersIdRoute +} + +const ApiUsersRouteChildren: ApiUsersRouteChildren = { + ApiUsersIdRoute: ApiUsersIdRoute, +} + +const ApiUsersRouteWithChildren = ApiUsersRoute._addFileChildren( + ApiUsersRouteChildren, +) + const rootRouteChildren: RootRouteChildren = { IndexRoute: IndexRoute, DeferredRoute: DeferredRoute, PostsRoute: PostsRouteWithChildren, UsersRoute: UsersRouteWithChildren, + ApiUsersRoute: ApiUsersRouteWithChildren, + PostsPostIdDeepRoute: PostsPostIdDeepRoute, } export const routeTree = rootRouteImport ._addFileChildren(rootRouteChildren) diff --git a/e2e/solid-start/basic-solid-query/src/router.tsx b/e2e/solid-start/basic-solid-query/src/router.tsx index f93fb9061e..c090958c01 100644 --- a/e2e/solid-start/basic-solid-query/src/router.tsx +++ b/e2e/solid-start/basic-solid-query/src/router.tsx @@ -27,4 +27,4 @@ export function getRouter() { queryClient, }) return router -} \ No newline at end of file +} diff --git a/e2e/solid-start/basic-solid-query/src/routes/__root.tsx b/e2e/solid-start/basic-solid-query/src/routes/__root.tsx index 4af6a08ab9..737926dd27 100644 --- a/e2e/solid-start/basic-solid-query/src/routes/__root.tsx +++ b/e2e/solid-start/basic-solid-query/src/routes/__root.tsx @@ -122,4 +122,4 @@ function RootDocument(props: { children?: any }) { ) -} \ No newline at end of file +} diff --git a/e2e/solid-start/basic-solid-query/src/routes/api.users.ts b/e2e/solid-start/basic-solid-query/src/routes/api.users.ts new file mode 100644 index 0000000000..37e6e2f9c3 --- /dev/null +++ b/e2e/solid-start/basic-solid-query/src/routes/api.users.ts @@ -0,0 +1,25 @@ +import { createFileRoute } from '@tanstack/solid-router' +import { json } from '@tanstack/solid-start' +import axios from 'redaxios' +import type { User } from '../utils/users' + +let queryURL = 'https://jsonplaceholder.typicode.com' + +if (import.meta.env.VITE_NODE_ENV === 'test') { + queryURL = `http://localhost:${import.meta.env.VITE_EXTERNAL_PORT}` +} + +export const Route = createFileRoute('/api/users')({ + server: { + handlers: { + GET: async ({ request }) => { + console.info('Fetching users... @', request.url) + const res = await axios.get>(`${queryURL}/users`) + const list = res.data.slice(0, 10) + return json( + list.map((u) => ({ id: u.id, name: u.name, email: u.email })), + ) + }, + }, + }, +}) diff --git a/e2e/solid-start/basic-solid-query/src/routes/api/users.$id.ts b/e2e/solid-start/basic-solid-query/src/routes/api/users.$id.ts new file mode 100644 index 0000000000..4a1503f0d7 --- /dev/null +++ b/e2e/solid-start/basic-solid-query/src/routes/api/users.$id.ts @@ -0,0 +1,31 @@ +import { createFileRoute } from '@tanstack/solid-router' +import { json } from '@tanstack/solid-start' +import axios from 'redaxios' +import type { User } from '../../utils/users' + +let queryURL = 'https://jsonplaceholder.typicode.com' + +if (import.meta.env.VITE_NODE_ENV === 'test') { + queryURL = `http://localhost:${import.meta.env.VITE_EXTERNAL_PORT}` +} + +export const Route = createFileRoute('/api/users/$id')({ + server: { + handlers: { + GET: async ({ request, params }) => { + console.info(`Fetching users by id=${params.id}... @`, request.url) + try { + const res = await axios.get(`${queryURL}/users/` + params.id) + return json({ + id: res.data.id, + name: res.data.name, + email: res.data.email, + }) + } catch (e) { + console.error(e) + return json({ error: 'User not found' }, { status: 404 }) + } + }, + }, + }, +}) diff --git a/e2e/solid-start/basic-solid-query/src/routes/deferred.tsx b/e2e/solid-start/basic-solid-query/src/routes/deferred.tsx index 2fa71ccbb5..0e0ced4be6 100644 --- a/e2e/solid-start/basic-solid-query/src/routes/deferred.tsx +++ b/e2e/solid-start/basic-solid-query/src/routes/deferred.tsx @@ -51,4 +51,4 @@ function DeferredQuery() {
    Time: {data() ? new Date(data()!.time).toISOString() : ''}
    ) -} \ No newline at end of file +} diff --git a/e2e/solid-start/basic-solid-query/src/routes/index.tsx b/e2e/solid-start/basic-solid-query/src/routes/index.tsx index ab597c885d..bdfb4c7676 100644 --- a/e2e/solid-start/basic-solid-query/src/routes/index.tsx +++ b/e2e/solid-start/basic-solid-query/src/routes/index.tsx @@ -10,4 +10,4 @@ function Home() {

    Welcome Home!

    ) -} \ No newline at end of file +} diff --git a/e2e/solid-start/basic-solid-query/src/routes/posts.$postId.tsx b/e2e/solid-start/basic-solid-query/src/routes/posts.$postId.tsx index 6bc5e644e8..ad8f878967 100644 --- a/e2e/solid-start/basic-solid-query/src/routes/posts.$postId.tsx +++ b/e2e/solid-start/basic-solid-query/src/routes/posts.$postId.tsx @@ -1,5 +1,5 @@ import { useQuery } from '@tanstack/solid-query' -import { ErrorComponent, createFileRoute } from '@tanstack/solid-router' +import { ErrorComponent, Link, createFileRoute } from '@tanstack/solid-router' import { postQueryOptions } from '~/utils/posts' export const Route = createFileRoute('/posts/$postId')({ @@ -22,6 +22,16 @@ function PostComponent() {

    {postQuery.data?.title}

    {postQuery.data?.body}
    + + Deep View +
    ) -} \ No newline at end of file +} diff --git a/e2e/solid-start/basic-solid-query/src/routes/posts.index.tsx b/e2e/solid-start/basic-solid-query/src/routes/posts.index.tsx index 70a2ce932e..33d0386c19 100644 --- a/e2e/solid-start/basic-solid-query/src/routes/posts.index.tsx +++ b/e2e/solid-start/basic-solid-query/src/routes/posts.index.tsx @@ -6,4 +6,4 @@ export const Route = createFileRoute('/posts/')({ function PostsIndexComponent() { return
    Select a post.
    -} \ No newline at end of file +} diff --git a/e2e/solid-start/basic-solid-query/src/routes/posts.tsx b/e2e/solid-start/basic-solid-query/src/routes/posts.tsx index 0e46c8c569..8d198b5a2d 100644 --- a/e2e/solid-start/basic-solid-query/src/routes/posts.tsx +++ b/e2e/solid-start/basic-solid-query/src/routes/posts.tsx @@ -45,4 +45,4 @@ function PostsComponent() { ) -} \ No newline at end of file +} diff --git a/e2e/solid-start/basic-solid-query/src/routes/posts_.$postId.deep.tsx b/e2e/solid-start/basic-solid-query/src/routes/posts_.$postId.deep.tsx new file mode 100644 index 0000000000..9352a3d086 --- /dev/null +++ b/e2e/solid-start/basic-solid-query/src/routes/posts_.$postId.deep.tsx @@ -0,0 +1,36 @@ +import { Link, createFileRoute } from '@tanstack/solid-router' +import { useQuery } from '@tanstack/solid-query' +import { postQueryOptions } from '../utils/posts' +import { PostErrorComponent } from './posts.$postId' + +export const Route = createFileRoute('/posts_/$postId/deep')({ + loader: async ({ params: { postId }, context }) => { + const data = await context.queryClient.ensureQueryData( + postQueryOptions(postId), + ) + + return { + title: data.title, + } + }, + head: ({ loaderData }) => ({ + meta: loaderData ? [{ title: loaderData.title }] : undefined, + }), + errorComponent: PostErrorComponent, + component: PostDeepComponent, +}) + +function PostDeepComponent() { + const params = Route.useParams() + const postQuery = useQuery(() => postQueryOptions(params().postId)) + + return ( +
    + + ← All Posts + +

    {postQuery.data?.title}

    +
    {postQuery.data?.body}
    +
    + ) +} diff --git a/e2e/solid-start/basic-solid-query/src/routes/users.$userId.tsx b/e2e/solid-start/basic-solid-query/src/routes/users.$userId.tsx index 3fc005838d..71e4b765b4 100644 --- a/e2e/solid-start/basic-solid-query/src/routes/users.$userId.tsx +++ b/e2e/solid-start/basic-solid-query/src/routes/users.$userId.tsx @@ -16,7 +16,7 @@ export const Route = createFileRoute('/users/$userId')({ }, }) -export function UserErrorComponent(props: ErrorComponentProps) { +function UserErrorComponent(props: ErrorComponentProps) { return } @@ -27,8 +27,10 @@ function UserComponent() { return (
    -

    {user()?.name ?? 'loading...'}

    +

    + {user()?.name ?? 'loading...'} +

    {user()?.email ?? ''}
    ) -} \ No newline at end of file +} diff --git a/e2e/solid-start/basic-solid-query/src/routes/users.index.tsx b/e2e/solid-start/basic-solid-query/src/routes/users.index.tsx index 4943ea7586..bbc96801a9 100644 --- a/e2e/solid-start/basic-solid-query/src/routes/users.index.tsx +++ b/e2e/solid-start/basic-solid-query/src/routes/users.index.tsx @@ -6,4 +6,4 @@ export const Route = createFileRoute('/users/')({ function UsersIndexComponent() { return
    Select a user.
    -} \ No newline at end of file +} diff --git a/e2e/solid-start/basic-solid-query/src/routes/users.tsx b/e2e/solid-start/basic-solid-query/src/routes/users.tsx index 091b75a4d9..d957122a6e 100644 --- a/e2e/solid-start/basic-solid-query/src/routes/users.tsx +++ b/e2e/solid-start/basic-solid-query/src/routes/users.tsx @@ -43,4 +43,4 @@ function UsersComponent() { ) -} \ No newline at end of file +} diff --git a/e2e/solid-start/basic-solid-query/src/styles/app.css b/e2e/solid-start/basic-solid-query/src/styles/app.css index 5a98003653..401c9469b2 100644 --- a/e2e/solid-start/basic-solid-query/src/styles/app.css +++ b/e2e/solid-start/basic-solid-query/src/styles/app.css @@ -5,4 +5,4 @@ body { @apply text-base; font-family: system-ui, sans-serif; -} \ No newline at end of file +} diff --git a/e2e/solid-start/basic-solid-query/src/utils/posts.tsx b/e2e/solid-start/basic-solid-query/src/utils/posts.tsx index 88013e8c82..c280c9bfbf 100644 --- a/e2e/solid-start/basic-solid-query/src/utils/posts.tsx +++ b/e2e/solid-start/basic-solid-query/src/utils/posts.tsx @@ -30,4 +30,4 @@ export const postQueryOptions = (postId: string) => .get(`https://jsonplaceholder.typicode.com/posts/${postId}`) .then((r) => r.data) }, - }) \ No newline at end of file + }) diff --git a/e2e/solid-start/basic-solid-query/src/utils/seo.ts b/e2e/solid-start/basic-solid-query/src/utils/seo.ts index 60e0fcf8e7..f909e9e5fc 100644 --- a/e2e/solid-start/basic-solid-query/src/utils/seo.ts +++ b/e2e/solid-start/basic-solid-query/src/utils/seo.ts @@ -27,4 +27,4 @@ export function seo(params: { ] return tags -} \ No newline at end of file +} diff --git a/e2e/solid-start/basic-solid-query/src/utils/users.tsx b/e2e/solid-start/basic-solid-query/src/utils/users.tsx index 5811147c40..52d659b001 100644 --- a/e2e/solid-start/basic-solid-query/src/utils/users.tsx +++ b/e2e/solid-start/basic-solid-query/src/utils/users.tsx @@ -34,4 +34,4 @@ export const userQueryOptions = (id: string) => .catch(() => { throw new Error('Failed to fetch user') }), - }) \ No newline at end of file + }) diff --git a/e2e/solid-start/basic-solid-query/tailwind.config.mjs b/e2e/solid-start/basic-solid-query/tailwind.config.mjs index f2cff365ba..be882983bf 100644 --- a/e2e/solid-start/basic-solid-query/tailwind.config.mjs +++ b/e2e/solid-start/basic-solid-query/tailwind.config.mjs @@ -5,4 +5,4 @@ export default { extend: {}, }, plugins: [], -} \ No newline at end of file +} diff --git a/e2e/solid-start/basic-solid-query/tests/app.spec.ts b/e2e/solid-start/basic-solid-query/tests/app.spec.ts index 976f49ca4b..ed111dd0b8 100644 --- a/e2e/solid-start/basic-solid-query/tests/app.spec.ts +++ b/e2e/solid-start/basic-solid-query/tests/app.spec.ts @@ -16,21 +16,3 @@ test('Navigating to user', async ({ page }) => { await page.getByRole('link', { name: 'Leanne Graham' }).click() await expect(page.getByRole('heading')).toContainText('Leanne Graham') }) - -test('Navigating nested layouts', async ({ page }) => { - await page.goto('/') - - await page.getByRole('link', { name: 'Layout', exact: true }).click() - await page.getByRole('link', { name: 'Layout A' }).click() - await expect(page.locator('body')).toContainText("I'm A!") - await page.getByRole('link', { name: 'Layout B' }).click() - await expect(page.locator('body')).toContainText("I'm B!") -}) - -test('Navigating to a not-found route', async ({ page }) => { - await page.goto('/') - - await page.getByRole('link', { name: 'This Route Does Not Exist' }).click() - await page.getByRole('link', { name: 'Start Over' }).click() - await expect(page.getByRole('heading')).toContainText('Welcome Home!') -}) \ No newline at end of file diff --git a/e2e/solid-start/basic-solid-query/tests/setup/global.setup.ts b/e2e/solid-start/basic-solid-query/tests/setup/global.setup.ts index 03c095d5fc..3593d10ab9 100644 --- a/e2e/solid-start/basic-solid-query/tests/setup/global.setup.ts +++ b/e2e/solid-start/basic-solid-query/tests/setup/global.setup.ts @@ -1 +1,6 @@ -export default function () {} \ No newline at end of file +import { e2eStartDummyServer } from '@tanstack/router-e2e-utils' +import packageJson from '../../package.json' with { type: 'json' } + +export default async function setup() { + await e2eStartDummyServer(packageJson.name) +} diff --git a/e2e/solid-start/basic-solid-query/tests/setup/global.teardown.ts b/e2e/solid-start/basic-solid-query/tests/setup/global.teardown.ts index 03c095d5fc..62fd79911c 100644 --- a/e2e/solid-start/basic-solid-query/tests/setup/global.teardown.ts +++ b/e2e/solid-start/basic-solid-query/tests/setup/global.teardown.ts @@ -1 +1,6 @@ -export default function () {} \ No newline at end of file +import { e2eStopDummyServer } from '@tanstack/router-e2e-utils' +import packageJson from '../../package.json' with { type: 'json' } + +export default async function teardown() { + await e2eStopDummyServer(packageJson.name) +} diff --git a/e2e/solid-start/basic-solid-query/tsconfig.json b/e2e/solid-start/basic-solid-query/tsconfig.json index 88ba4e9537..ed8b73fa2d 100644 --- a/e2e/solid-start/basic-solid-query/tsconfig.json +++ b/e2e/solid-start/basic-solid-query/tsconfig.json @@ -21,4 +21,4 @@ "noEmit": true, "types": ["vite/client"] } -} \ No newline at end of file +} diff --git a/e2e/solid-start/basic-solid-query/vite.config.ts b/e2e/solid-start/basic-solid-query/vite.config.ts index 37ea52c2f9..a0ce060b3a 100644 --- a/e2e/solid-start/basic-solid-query/vite.config.ts +++ b/e2e/solid-start/basic-solid-query/vite.config.ts @@ -11,4 +11,4 @@ export default defineConfig({ tanstackStart(), solid({ ssr: true }), ], -}) \ No newline at end of file +}) diff --git a/e2e/solid-start/query-integration/package.json b/e2e/solid-start/query-integration/package.json index f37c196dd1..53ea397f33 100644 --- a/e2e/solid-start/query-integration/package.json +++ b/e2e/solid-start/query-integration/package.json @@ -33,4 +33,4 @@ "vite-plugin-solid": "^2.11.8", "vite-tsconfig-paths": "^5.1.4" } -} \ No newline at end of file +} diff --git a/e2e/solid-start/query-integration/playwright.config.ts b/e2e/solid-start/query-integration/playwright.config.ts index ae6bbca58e..c09b27e29f 100644 --- a/e2e/solid-start/query-integration/playwright.config.ts +++ b/e2e/solid-start/query-integration/playwright.config.ts @@ -33,4 +33,4 @@ export default defineConfig({ use: { ...devices['Desktop Chrome'] }, }, ], -}) \ No newline at end of file +}) diff --git a/e2e/solid-start/query-integration/postcss.config.mjs b/e2e/solid-start/query-integration/postcss.config.mjs index e99ebc2c0e..2e7af2b7f1 100644 --- a/e2e/solid-start/query-integration/postcss.config.mjs +++ b/e2e/solid-start/query-integration/postcss.config.mjs @@ -3,4 +3,4 @@ export default { tailwindcss: {}, autoprefixer: {}, }, -} \ No newline at end of file +} diff --git a/e2e/solid-start/query-integration/src/queryOptions.ts b/e2e/solid-start/query-integration/src/queryOptions.ts index 77385e7987..10a5073f5e 100644 --- a/e2e/solid-start/query-integration/src/queryOptions.ts +++ b/e2e/solid-start/query-integration/src/queryOptions.ts @@ -13,4 +13,4 @@ export const makeQueryOptions = (key: string) => return result }, staleTime: Infinity, - }) \ No newline at end of file + }) diff --git a/e2e/solid-start/query-integration/src/router.tsx b/e2e/solid-start/query-integration/src/router.tsx index 936abb1ea4..dcd13f0fda 100644 --- a/e2e/solid-start/query-integration/src/router.tsx +++ b/e2e/solid-start/query-integration/src/router.tsx @@ -23,4 +23,4 @@ export function getRouter() { queryClient, }) return router -} \ No newline at end of file +} diff --git a/e2e/solid-start/query-integration/src/routes/__root.tsx b/e2e/solid-start/query-integration/src/routes/__root.tsx index 3860622760..8c5639a42b 100644 --- a/e2e/solid-start/query-integration/src/routes/__root.tsx +++ b/e2e/solid-start/query-integration/src/routes/__root.tsx @@ -81,4 +81,4 @@ function RootDocument(props: { children?: any }) { ) -} \ No newline at end of file +} diff --git a/e2e/solid-start/query-integration/src/routes/index.tsx b/e2e/solid-start/query-integration/src/routes/index.tsx index 93a143cc2d..144674be76 100644 --- a/e2e/solid-start/query-integration/src/routes/index.tsx +++ b/e2e/solid-start/query-integration/src/routes/index.tsx @@ -10,4 +10,4 @@ function Home() {

    Query Integration E2E tests

    ) -} \ No newline at end of file +} diff --git a/e2e/solid-start/query-integration/src/routes/loader-fetchQuery/$type.tsx b/e2e/solid-start/query-integration/src/routes/loader-fetchQuery/$type.tsx index ebd34b63f9..479a1f8070 100644 --- a/e2e/solid-start/query-integration/src/routes/loader-fetchQuery/$type.tsx +++ b/e2e/solid-start/query-integration/src/routes/loader-fetchQuery/$type.tsx @@ -19,7 +19,9 @@ export const Route = createFileRoute('/loader-fetchQuery/$type')({ loader: async ({ context, params }) => { await context.queryClient.ensureQueryData(context.queryOptions) if (params.type === 'sync') { - return context.queryClient.getQueryData(context.queryOptions.queryKey) as string + return context.queryClient.getQueryData( + context.queryOptions.queryKey, + ) as string } return undefined as any }, @@ -35,11 +37,13 @@ function RouteComponent() { return (
    - loader data:
    {loaderData() ?? 'undefined'}
    + loader data:{' '} +
    {loaderData() ?? 'undefined'}
    - query data:
    {query.data ?? 'loading...'}
    + query data:{' '} +
    {query.data ?? 'loading...'}
    ) -} \ No newline at end of file +} diff --git a/e2e/solid-start/query-integration/src/routes/useQuery.tsx b/e2e/solid-start/query-integration/src/routes/useQuery.tsx index f4a2103f70..669cd454a6 100644 --- a/e2e/solid-start/query-integration/src/routes/useQuery.tsx +++ b/e2e/solid-start/query-integration/src/routes/useQuery.tsx @@ -16,8 +16,9 @@ function RouteComponent() { return (
    - query data:
    {query.data ?? 'loading...'}
    + query data:{' '} +
    {query.data ?? 'loading...'}
    ) -} \ No newline at end of file +} diff --git a/e2e/solid-start/query-integration/src/styles/app.css b/e2e/solid-start/query-integration/src/styles/app.css index 5a98003653..401c9469b2 100644 --- a/e2e/solid-start/query-integration/src/styles/app.css +++ b/e2e/solid-start/query-integration/src/styles/app.css @@ -5,4 +5,4 @@ body { @apply text-base; font-family: system-ui, sans-serif; -} \ No newline at end of file +} diff --git a/e2e/solid-start/query-integration/tailwind.config.mjs b/e2e/solid-start/query-integration/tailwind.config.mjs index f2cff365ba..be882983bf 100644 --- a/e2e/solid-start/query-integration/tailwind.config.mjs +++ b/e2e/solid-start/query-integration/tailwind.config.mjs @@ -5,4 +5,4 @@ export default { extend: {}, }, plugins: [], -} \ No newline at end of file +} diff --git a/e2e/solid-start/query-integration/tsconfig.json b/e2e/solid-start/query-integration/tsconfig.json index 88ba4e9537..ed8b73fa2d 100644 --- a/e2e/solid-start/query-integration/tsconfig.json +++ b/e2e/solid-start/query-integration/tsconfig.json @@ -21,4 +21,4 @@ "noEmit": true, "types": ["vite/client"] } -} \ No newline at end of file +} diff --git a/e2e/solid-start/query-integration/vite.config.ts b/e2e/solid-start/query-integration/vite.config.ts index 37ea52c2f9..a0ce060b3a 100644 --- a/e2e/solid-start/query-integration/vite.config.ts +++ b/e2e/solid-start/query-integration/vite.config.ts @@ -11,4 +11,4 @@ export default defineConfig({ tanstackStart(), solid({ ssr: true }), ], -}) \ No newline at end of file +}) diff --git a/packages/solid-router-ssr-query/README.md b/packages/solid-router-ssr-query/README.md index d0a08dc3e5..7311580061 100644 --- a/packages/solid-router-ssr-query/README.md +++ b/packages/solid-router-ssr-query/README.md @@ -35,4 +35,4 @@ setupRouterSsrQueryIntegration({ ## License -MIT \ No newline at end of file +MIT diff --git a/packages/solid-router-ssr-query/eslint.config.js b/packages/solid-router-ssr-query/eslint.config.js index 381a097af3..df59eb36f3 100644 --- a/packages/solid-router-ssr-query/eslint.config.js +++ b/packages/solid-router-ssr-query/eslint.config.js @@ -9,4 +9,4 @@ export default [ files: ['**/*.{ts,tsx}'], ...pluginSolid, }, -] \ No newline at end of file +] diff --git a/packages/solid-router-ssr-query/package.json b/packages/solid-router-ssr-query/package.json index 2cf8bea6e5..aca33ee277 100644 --- a/packages/solid-router-ssr-query/package.json +++ b/packages/solid-router-ssr-query/package.json @@ -64,18 +64,19 @@ "node": ">=12" }, "dependencies": { - "@tanstack/router-ssr-query-core": "workspace:*" + "@tanstack/router-ssr-query-core": "workspace:*", + "eslint-plugin-solid": "^0.14.5" }, "devDependencies": { - "vite-plugin-solid": "^2.11.8", - "solid-js": "^1.9.5", + "@tanstack/solid-query": ">=5.66.0", "@tanstack/solid-router": "workspace:*", - "@tanstack/solid-query": ">=5.66.0" + "solid-js": "^1.9.5", + "vite-plugin-solid": "^2.11.8" }, "peerDependencies": { - "solid-js": "^1.9.5", "@tanstack/query-core": ">=5.66.0", + "@tanstack/solid-query": ">=5.66.2", "@tanstack/solid-router": ">=1.127.0", - "@tanstack/solid-query": ">=5.66.2" + "solid-js": "^1.9.5" } -} \ No newline at end of file +} diff --git a/packages/solid-router-ssr-query/src/index.tsx b/packages/solid-router-ssr-query/src/index.tsx index a7630d0a34..91f764f15f 100644 --- a/packages/solid-router-ssr-query/src/index.tsx +++ b/packages/solid-router-ssr-query/src/index.tsx @@ -17,8 +17,10 @@ export function setupRouterSsrQueryIntegration( if (opts.wrapQueryClient === false) { return } - - const OGWrap = opts.router.options.Wrap || ((props: { children: JSX.Element }) => props.children) + + const OGWrap = + opts.router.options.Wrap || + ((props: { children: JSX.Element }) => props.children) opts.router.options.Wrap = (props) => { return ( @@ -27,4 +29,4 @@ export function setupRouterSsrQueryIntegration( ) } -} \ No newline at end of file +} diff --git a/packages/solid-router-ssr-query/tsconfig.json b/packages/solid-router-ssr-query/tsconfig.json index cf877483c0..e24672b5de 100644 --- a/packages/solid-router-ssr-query/tsconfig.json +++ b/packages/solid-router-ssr-query/tsconfig.json @@ -5,4 +5,4 @@ "jsxImportSource": "solid-js" }, "include": ["src", "tests", "vite.config.ts"] -} \ No newline at end of file +} diff --git a/packages/solid-router-ssr-query/vite.config.ts b/packages/solid-router-ssr-query/vite.config.ts index 3c681ed252..b78cdf1373 100644 --- a/packages/solid-router-ssr-query/vite.config.ts +++ b/packages/solid-router-ssr-query/vite.config.ts @@ -21,4 +21,4 @@ export default mergeConfig( entry: './src/index.tsx', srcDir: './src', }), -) \ No newline at end of file +) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5c09b70596..0d88426cf1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5432,7 +5432,7 @@ importers: version: 7.1.7(@types/node@22.10.2)(jiti@2.6.0)(lightningcss@1.30.1)(terser@5.37.0)(tsx@4.20.3)(yaml@2.7.0) vitest: specifier: ^3.2.4 - version: 3.2.4(@types/node@22.10.2)(@vitest/browser@3.0.6)(@vitest/ui@3.0.6)(jiti@2.6.0)(jsdom@27.0.0(postcss@8.5.6))(lightningcss@1.30.1)(msw@2.7.0(@types/node@22.10.2)(typescript@5.9.2))(terser@5.37.0)(tsx@4.20.3)(yaml@2.7.0) + version: 3.2.4(@types/node@22.10.2)(@vitest/browser@3.0.6(@types/node@22.10.2)(playwright@1.52.0)(typescript@5.9.2)(vite@7.1.7(@types/node@22.10.2)(jiti@2.6.0)(lightningcss@1.30.1)(terser@5.37.0)(tsx@4.20.3)(yaml@2.7.0))(vitest@3.2.4))(@vitest/ui@3.0.6(vitest@3.2.4))(jiti@2.6.0)(jsdom@27.0.0(postcss@8.5.6))(lightningcss@1.30.1)(msw@2.7.0(@types/node@22.10.2)(typescript@5.9.2))(terser@5.37.0)(tsx@4.20.3)(yaml@2.7.0) web-vitals: specifier: ^5.1.0 version: 5.1.0 @@ -7391,6 +7391,9 @@ importers: '@tanstack/router-ssr-query-core': specifier: workspace:* version: link:../router-ssr-query-core + eslint-plugin-solid: + specifier: ^0.14.5 + version: 0.14.5(eslint@9.22.0(jiti@2.6.0))(typescript@5.9.2) devDependencies: '@tanstack/solid-query': specifier: '>=5.66.0' @@ -18206,7 +18209,7 @@ snapshots: '@eslint-react/eff': 1.26.2 '@typescript-eslint/types': 8.23.0 '@typescript-eslint/typescript-estree': 8.23.0(typescript@5.9.2) - '@typescript-eslint/utils': 8.23.0(eslint@9.22.0(jiti@2.6.0))(typescript@5.9.2) + '@typescript-eslint/utils': 8.44.1(eslint@9.22.0(jiti@2.6.0))(typescript@5.9.2) string-ts: 2.2.1 ts-pattern: 5.6.2 transitivePeerDependencies: @@ -18224,7 +18227,7 @@ snapshots: '@typescript-eslint/scope-manager': 8.23.0 '@typescript-eslint/type-utils': 8.23.0(eslint@9.22.0(jiti@2.6.0))(typescript@5.9.2) '@typescript-eslint/types': 8.23.0 - '@typescript-eslint/utils': 8.23.0(eslint@9.22.0(jiti@2.6.0))(typescript@5.9.2) + '@typescript-eslint/utils': 8.44.1(eslint@9.22.0(jiti@2.6.0))(typescript@5.9.2) birecord: 0.1.1 ts-pattern: 5.6.2 transitivePeerDependencies: @@ -18262,7 +18265,7 @@ snapshots: '@eslint-react/var': 1.26.2(eslint@9.22.0(jiti@2.6.0))(typescript@5.9.2) '@typescript-eslint/scope-manager': 8.23.0 '@typescript-eslint/types': 8.23.0 - '@typescript-eslint/utils': 8.23.0(eslint@9.22.0(jiti@2.6.0))(typescript@5.9.2) + '@typescript-eslint/utils': 8.44.1(eslint@9.22.0(jiti@2.6.0))(typescript@5.9.2) ts-pattern: 5.6.2 transitivePeerDependencies: - eslint @@ -18286,7 +18289,7 @@ snapshots: '@eslint-react/eff': 1.26.2 '@typescript-eslint/scope-manager': 8.23.0 '@typescript-eslint/types': 8.23.0 - '@typescript-eslint/utils': 8.23.0(eslint@9.22.0(jiti@2.6.0))(typescript@5.9.2) + '@typescript-eslint/utils': 8.44.1(eslint@9.22.0(jiti@2.6.0))(typescript@5.9.2) string-ts: 2.2.1 ts-pattern: 5.6.2 transitivePeerDependencies: @@ -23508,7 +23511,7 @@ snapshots: eslint-plugin-solid@0.14.5(eslint@9.22.0(jiti@2.6.0))(typescript@5.9.2): dependencies: - '@typescript-eslint/utils': 8.23.0(eslint@9.22.0(jiti@2.6.0))(typescript@5.9.2) + '@typescript-eslint/utils': 8.44.1(eslint@9.22.0(jiti@2.6.0))(typescript@5.9.2) eslint: 9.22.0(jiti@2.6.0) estraverse: 5.3.0 is-html: 2.0.0 @@ -27251,7 +27254,7 @@ snapshots: optionalDependencies: vite: 7.1.7(@types/node@22.10.2)(jiti@2.6.0)(lightningcss@1.30.1)(terser@5.37.0)(tsx@4.20.3)(yaml@2.7.0) - vitest@3.2.4(@types/node@22.10.2)(@vitest/browser@3.0.6)(@vitest/ui@3.0.6)(jiti@2.6.0)(jsdom@25.0.1)(lightningcss@1.30.1)(msw@2.7.0(@types/node@22.10.2)(typescript@5.9.2))(terser@5.37.0)(tsx@4.20.3)(yaml@2.7.0): + vitest@3.2.4(@types/node@22.10.2)(@vitest/browser@3.0.6(@types/node@22.10.2)(playwright@1.52.0)(typescript@5.9.2)(vite@7.1.7(@types/node@22.10.2)(jiti@2.6.0)(lightningcss@1.30.1)(terser@5.37.0)(tsx@4.20.3)(yaml@2.7.0))(vitest@3.2.4))(@vitest/ui@3.0.6(vitest@3.2.4))(jiti@2.6.0)(jsdom@27.0.0(postcss@8.5.6))(lightningcss@1.30.1)(msw@2.7.0(@types/node@22.10.2)(typescript@5.9.2))(terser@5.37.0)(tsx@4.20.3)(yaml@2.7.0): dependencies: '@types/chai': 5.2.2 '@vitest/expect': 3.2.4 @@ -27280,7 +27283,7 @@ snapshots: '@types/node': 22.10.2 '@vitest/browser': 3.0.6(@types/node@22.10.2)(playwright@1.52.0)(typescript@5.9.2)(vite@7.1.7(@types/node@22.10.2)(jiti@2.6.0)(lightningcss@1.30.1)(terser@5.37.0)(tsx@4.20.3)(yaml@2.7.0))(vitest@3.2.4) '@vitest/ui': 3.0.6(vitest@3.2.4) - jsdom: 25.0.1 + jsdom: 27.0.0(postcss@8.5.6) transitivePeerDependencies: - jiti - less @@ -27295,7 +27298,7 @@ snapshots: - tsx - yaml - vitest@3.2.4(@types/node@22.10.2)(@vitest/browser@3.0.6)(@vitest/ui@3.0.6)(jiti@2.6.0)(jsdom@27.0.0(postcss@8.5.6))(lightningcss@1.30.1)(msw@2.7.0(@types/node@22.10.2)(typescript@5.9.2))(terser@5.37.0)(tsx@4.20.3)(yaml@2.7.0): + vitest@3.2.4(@types/node@22.10.2)(@vitest/browser@3.0.6)(@vitest/ui@3.0.6)(jiti@2.6.0)(jsdom@25.0.1)(lightningcss@1.30.1)(msw@2.7.0(@types/node@22.10.2)(typescript@5.9.2))(terser@5.37.0)(tsx@4.20.3)(yaml@2.7.0): dependencies: '@types/chai': 5.2.2 '@vitest/expect': 3.2.4 @@ -27324,7 +27327,7 @@ snapshots: '@types/node': 22.10.2 '@vitest/browser': 3.0.6(@types/node@22.10.2)(playwright@1.52.0)(typescript@5.9.2)(vite@7.1.7(@types/node@22.10.2)(jiti@2.6.0)(lightningcss@1.30.1)(terser@5.37.0)(tsx@4.20.3)(yaml@2.7.0))(vitest@3.2.4) '@vitest/ui': 3.0.6(vitest@3.2.4) - jsdom: 27.0.0(postcss@8.5.6) + jsdom: 25.0.1 transitivePeerDependencies: - jiti - less From e2e737a8076980f7004f214fbf4f53cc7fff8a16 Mon Sep 17 00:00:00 2001 From: Birk Skyum Date: Wed, 1 Oct 2025 14:10:24 +0200 Subject: [PATCH 3/3] remove playwright report --- .../playwright-report/index.html | 19508 ---------------- 1 file changed, 19508 deletions(-) delete mode 100644 e2e/solid-start/basic-solid-query/playwright-report/index.html diff --git a/e2e/solid-start/basic-solid-query/playwright-report/index.html b/e2e/solid-start/basic-solid-query/playwright-report/index.html deleted file mode 100644 index 98601962cc..0000000000 --- a/e2e/solid-start/basic-solid-query/playwright-report/index.html +++ /dev/null @@ -1,19508 +0,0 @@ - - - - - - - Playwright Test Report - - - - -
    - - -