-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
test(solid-start): add virtual-routes e2e suite #5556
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| node_modules | ||
| package-lock.json | ||
| yarn.lock | ||
|
|
||
| .DS_Store | ||
| .cache | ||
| .env | ||
| .vercel | ||
| .output | ||
|
|
||
| /build/ | ||
| /api/ | ||
| /server/build | ||
| /public/build | ||
| # Sentry Config File | ||
| .env.sentry-build-plugin | ||
| /test-results/ | ||
| /playwright-report/ | ||
| /blob-report/ | ||
| /playwright/.cache/ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| **/build | ||
| **/public | ||
| pnpm-lock.yaml | ||
| routeTree.gen.ts |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| { | ||
| "name": "tanstack-solid-start-e2e-virtual-routes", | ||
| "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-router": "workspace:^", | ||
| "@tanstack/solid-router-devtools": "workspace:^", | ||
| "@tanstack/solid-start": "workspace:^", | ||
| "@tanstack/virtual-file-routes": "workspace:^", | ||
| "solid-js": "^1.9.5", | ||
| "redaxios": "^0.5.1", | ||
| "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", | ||
| "vite-plugin-solid": "^2.11.9", | ||
| "autoprefixer": "^10.4.20", | ||
| "combinate": "^1.1.11", | ||
| "postcss": "^8.5.1", | ||
| "srvx": "^0.8.6", | ||
| "tailwindcss": "^3.4.17", | ||
| "typescript": "^5.7.2", | ||
| "vite-tsconfig-paths": "^5.1.4" | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| 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}` | ||
|
|
||
| /** | ||
| * See https://playwright.dev/docs/test-configuration. | ||
| */ | ||
| export default defineConfig({ | ||
| testDir: './tests', | ||
| workers: 1, | ||
|
|
||
| reporter: [['line']], | ||
|
|
||
| globalSetup: './tests/setup/global.setup.ts', | ||
| globalTeardown: './tests/setup/global.teardown.ts', | ||
|
|
||
| use: { | ||
| /* Base URL to use in actions like `await page.goto('/')`. */ | ||
| baseURL, | ||
| }, | ||
|
|
||
| webServer: { | ||
| command: `VITE_NODE_ENV="test" VITE_EXTERNAL_PORT=${EXTERNAL_PORT} pnpm build && VITE_NODE_ENV="test" VITE_EXTERNAL_PORT=${EXTERNAL_PORT} VITE_SERVER_PORT=${PORT} PORT=${PORT} pnpm start`, | ||
| url: baseURL, | ||
| reuseExistingServer: !process.env.CI, | ||
| stdout: 'pipe', | ||
| }, | ||
|
|
||
| projects: [ | ||
| { | ||
| name: 'chromium', | ||
| use: { ...devices['Desktop Chrome'] }, | ||
| }, | ||
| ], | ||
| }) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| export default { | ||
| plugins: { | ||
| tailwindcss: {}, | ||
| autoprefixer: {}, | ||
| }, | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| console.log('SCRIPT_1 loaded') | ||
| window.SCRIPT_1 = true |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| console.log('SCRIPT_2 loaded') | ||
| window.SCRIPT_2 = true |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| { | ||
| "name": "", | ||
| "short_name": "", | ||
| "icons": [ | ||
| { | ||
| "src": "/android-chrome-192x192.png", | ||
| "sizes": "192x192", | ||
| "type": "image/png" | ||
| }, | ||
| { | ||
| "src": "/android-chrome-512x512.png", | ||
| "sizes": "512x512", | ||
| "type": "image/png" | ||
| } | ||
| ], | ||
| "theme_color": "#ffffff", | ||
| "background_color": "#ffffff", | ||
| "display": "standalone" | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| import { | ||
| index, | ||
| layout, | ||
| physical, | ||
| rootRoute, | ||
| route, | ||
| } from '@tanstack/virtual-file-routes' | ||
|
|
||
| export const routes = rootRoute('root.tsx', [ | ||
| index('home.tsx'), | ||
| route('/posts', 'posts/posts.tsx', [ | ||
| index('posts/posts-home.tsx'), | ||
| route('$postId', 'posts/posts-detail.tsx'), | ||
| ]), | ||
| layout('first', 'layout/first-layout.tsx', [ | ||
| layout('layout/second-layout.tsx', [ | ||
| route('route-without-file', [ | ||
| route('/layout-a', 'a.tsx'), | ||
| route('/layout-b', 'b.tsx'), | ||
| ]), | ||
| ]), | ||
| ]), | ||
| physical('/classic', 'file-based-subtree'), | ||
| ]) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| import { notFound } from '@tanstack/solid-router' | ||
| import axios from 'redaxios' | ||
|
|
||
| export type PostType = { | ||
| id: string | ||
| title: string | ||
| body: string | ||
| } | ||
|
|
||
| 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 fetchPost = async (postId: string) => { | ||
| console.info(`Fetching post with id ${postId}...`) | ||
| await new Promise((r) => setTimeout(r, 500)) | ||
| const post = await axios | ||
| .get<PostType>(`${queryURL}/posts/${postId}`) | ||
| .then((r) => r.data) | ||
| .catch((err) => { | ||
| if (err.status === 404) { | ||
| throw notFound() | ||
| } | ||
| throw err | ||
| }) | ||
|
Comment on lines
+22
to
+27
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chainVerify the error property for redaxios. The error handling checks 🌐 Web query: 💡 Result: Short answer: redaxios follows the Axios API for errors — the HTTP status code is on error.response.status (not error.status). The error object otherwise looks like a standard AxiosError (message, name, stack, config, code, request, response). Use optional chaining to be safe: const status = error.response?.status. Sources: redaxios package README (axios-compatible wrapper). [1] Axios error handling / AxiosError shape (shows error.response.status). [2] References Fix the error property access for redaxios in the error handler. The code checks 🤖 Prompt for AI Agents |
||
|
|
||
| return post | ||
| } | ||
|
|
||
| export const fetchPosts = async () => { | ||
| console.info('Fetching posts...') | ||
| await new Promise((r) => setTimeout(r, 500)) | ||
| return axios | ||
| .get<Array<PostType>>(`${queryURL}/posts`) | ||
| .then((r) => r.data.slice(0, 10)) | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
Verify the relative path in the start script.
The start script references
../clientwhich seems unusual. Ensure this path correctly points to the client output directory for the production server.🏁 Script executed:
Length of output: 0
🏁 Script executed:
Length of output: 4311
🏁 Script executed:
Length of output: 4234
🏁 Script executed:
Length of output: 553
🌐 Web query:
💡 Result:
Do you want the meaning/behavior of the --prod and -s flags for the srvx CLI, or examples of how to run them? I can look up the official docs and quote the CLI help—tell me which and I’ll fetch the exact docs.
🌐 Web query:
💡 Result:
dist/client is the client-side output of a Solid Start (Vite-based) build — it contains the static assets the browser needs: bundled JS/CSS for hydration, chunk files, asset files (images/fonts), and the Vite-generated client manifest/ssr-manifest used by server rendering. The server-side build (dist/server) contains the SSR/server bundle (handler) that imports the client manifest to emit correct asset tags and preload hints. In short:
Sources: Solid Start repo/docs (build layout and tooling), Vite SSR docs on client/server builds and ssr-manifest. [1][2][3]
References
[1] solidjs/solid-start (GitHub). (github.com)
[2] Vite — Server-Side Rendering / client+server build details (ssr-manifest). (v2.vitejs.dev)
[3] Solid Start "use server" / docs (shows server/client model in Solid Start). (docs.solidjs.com)
Citations:
🌐 Web query:
💡 Result:
Do you mean:
Which one do you want?
🏁 Script executed:
Length of output: 3030
Correct the start script to reference the actual client build output directory.
The
../clientpath does not exist in the repository. Solid Start builds client assets todist/clientduring the build process. The srvx command's-sflag should reference this directory to serve static files correctly.Change:
To:
This issue appears consistently across multiple Solid Start and React Start e2e projects, so the same fix should be applied to all affected projects.
🤖 Prompt for AI Agents