-
-
Notifications
You must be signed in to change notification settings - Fork 82
test(tanstack-start): Add e2e test application #1223
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
base: master
Are you sure you want to change the base?
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,6 @@ | ||
| node_modules | ||
| .DS_Store | ||
| .env | ||
| .output | ||
| .nitro | ||
| .tanstack |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| { | ||
| "name": "tanstack-start-test-app", | ||
| "private": true, | ||
| "type": "module", | ||
| "scripts": { | ||
| "dev": "vite dev", | ||
| "build": "vite build", | ||
| "start": "node .output/server/index.mjs" | ||
| }, | ||
| "dependencies": { | ||
| "@tanstack/react-router": "^1.132.0", | ||
| "@tanstack/react-start": "^1.132.0", | ||
| "@tanstack/router-plugin": "^1.132.0", | ||
| "nitro": "latest", | ||
| "react": "^19.2.0", | ||
| "react-dom": "^19.2.0", | ||
| "vite-tsconfig-paths": "^6.0.2" | ||
| }, | ||
| "devDependencies": { | ||
| "@types/react": "^19.2.0", | ||
| "@types/react-dom": "^19.2.0", | ||
| "@vitejs/plugin-react": "^5.0.4", | ||
| "typescript": "^5.7.2", | ||
| "vite": "^7.1.7" | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,68 @@ | ||
| /* 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 IndexRouteImport } from './routes/index' | ||
|
|
||
| const IndexRoute = IndexRouteImport.update({ | ||
| id: '/', | ||
| path: '/', | ||
| getParentRoute: () => rootRouteImport, | ||
| } as any) | ||
|
|
||
| export interface FileRoutesByFullPath { | ||
| '/': typeof IndexRoute | ||
| } | ||
| export interface FileRoutesByTo { | ||
| '/': typeof IndexRoute | ||
| } | ||
| export interface FileRoutesById { | ||
| __root__: typeof rootRouteImport | ||
| '/': typeof IndexRoute | ||
| } | ||
| export interface FileRouteTypes { | ||
| fileRoutesByFullPath: FileRoutesByFullPath | ||
| fullPaths: '/' | ||
| fileRoutesByTo: FileRoutesByTo | ||
| to: '/' | ||
| id: '__root__' | '/' | ||
| fileRoutesById: FileRoutesById | ||
| } | ||
| export interface RootRouteChildren { | ||
| IndexRoute: typeof IndexRoute | ||
| } | ||
|
|
||
| declare module '@tanstack/react-router' { | ||
| interface FileRoutesByPath { | ||
| '/': { | ||
| id: '/' | ||
| path: '/' | ||
| fullPath: '/' | ||
| preLoaderRoute: typeof IndexRouteImport | ||
| parentRoute: typeof rootRouteImport | ||
| } | ||
| } | ||
| } | ||
|
|
||
| const rootRouteChildren: RootRouteChildren = { | ||
| IndexRoute: IndexRoute, | ||
| } | ||
| export const routeTree = rootRouteImport | ||
| ._addFileChildren(rootRouteChildren) | ||
| ._addFileTypes<FileRouteTypes>() | ||
|
|
||
| import type { getRouter } from './router.tsx' | ||
| import type { createStart } from '@tanstack/react-start' | ||
| declare module '@tanstack/react-start' { | ||
| interface Register { | ||
| ssr: true | ||
| router: Awaited<ReturnType<typeof getRouter>> | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| import { createRouter } from '@tanstack/react-router'; | ||
| import { routeTree } from '@/routeTree.gen'; | ||
|
|
||
| export function getRouter() { | ||
| return createRouter({ | ||
| routeTree, | ||
| defaultPreload: 'intent', | ||
| scrollRestoration: true, | ||
| }); | ||
| } | ||
|
|
||
| declare module '@tanstack/react-router' { | ||
| interface Register { | ||
| router: ReturnType<typeof getRouter>; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| import { | ||
| HeadContent, | ||
| Outlet, | ||
| Scripts, | ||
| createRootRoute, | ||
| } from '@tanstack/react-router'; | ||
|
|
||
| export const Route = createRootRoute({ | ||
| head: () => ({ | ||
| meta: [ | ||
| { charSet: 'utf-8' }, | ||
| { name: 'viewport', content: 'width=device-width, initial-scale=1' }, | ||
| ], | ||
| }), | ||
| component: RootLayout, | ||
| }); | ||
|
|
||
| function RootLayout() { | ||
| return ( | ||
| <html> | ||
| <head> | ||
| <HeadContent /> | ||
| </head> | ||
| <body> | ||
| <Outlet /> | ||
| <Scripts /> | ||
| </body> | ||
| </html> | ||
| ); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| import { createFileRoute } from '@tanstack/react-router'; | ||
|
|
||
| export const Route = createFileRoute('/')({ | ||
| component: Home, | ||
| }); | ||
|
|
||
| function Home() { | ||
| return <h1>Home</h1>; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| { | ||
| "include": ["**/*.ts", "**/*.tsx"], | ||
| "compilerOptions": { | ||
| "target": "ES2022", | ||
| "jsx": "react-jsx", | ||
| "module": "ESNext", | ||
| "lib": ["ES2022", "DOM", "DOM.Iterable"], | ||
| "types": ["vite/client"], | ||
| "moduleResolution": "bundler", | ||
| "allowImportingTsExtensions": true, | ||
| "verbatimModuleSyntax": false, | ||
| "noEmit": true, | ||
| "skipLibCheck": true, | ||
| "strict": true, | ||
| "baseUrl": ".", | ||
| "paths": { | ||
| "@/*": ["./src/*"] | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| import { tanstackStart } from '@tanstack/react-start/plugin/vite'; | ||
| import { defineConfig } from 'vite'; | ||
| import tsConfigPaths from 'vite-tsconfig-paths'; | ||
| import viteReact from '@vitejs/plugin-react'; | ||
| import { nitro } from 'nitro/vite'; | ||
|
|
||
| export default defineConfig({ | ||
| plugins: [ | ||
| tsConfigPaths({ projects: ['./tsconfig.json'] }), | ||
| tanstackStart({ srcDirectory: 'src' }), | ||
| viteReact(), | ||
| nitro(), | ||
| ], | ||
| }); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| import { execSync } from 'node:child_process'; | ||
| import { | ||
| checkIfBuilds, | ||
| checkIfRunsOnDevMode, | ||
| checkIfRunsOnProdMode, | ||
| createIsolatedTestEnv, | ||
| } from '../utils'; | ||
| import { afterAll, beforeAll, describe, test } from 'vitest'; | ||
|
|
||
| describe('TanStack Start', () => { | ||
| const { projectDir, cleanup } = createIsolatedTestEnv( | ||
| 'tanstack-start-test-app', | ||
| ); | ||
|
|
||
| beforeAll(() => { | ||
| execSync('npm install', { cwd: projectDir, stdio: 'pipe' }); | ||
| }); | ||
|
|
||
| afterAll(() => { | ||
| cleanup(); | ||
| }); | ||
|
|
||
| test('builds successfully', async () => { | ||
| await checkIfBuilds(projectDir); | ||
| }); | ||
|
|
||
| test('runs on dev mode correctly', async () => { | ||
| await checkIfRunsOnDevMode(projectDir, 'ready in'); | ||
| }); | ||
|
|
||
| test('runs on prod mode correctly', async () => { | ||
nicohrubec marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| await checkIfRunsOnProdMode(projectDir, 'Listening on'); | ||
| }); | ||
|
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. Dev test before prod test corrupts build outputHigh Severity The
Member
Author
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. this is true for angular but not for other tests
Member
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. For me it was reproducible locally with It seems that tanstack doesn't like the
Locally I fixed it by changing the following in the ProcessRunner (not sure though if this is a valid fix): - this.taskHandle = spawn(cmd, args, { cwd: opts?.cwd, stdio: 'pipe' });
+ const { TEST: _test, ...envWithoutTest } = process.env;
+ this.taskHandle = spawn(cmd, args, {
+ cwd: opts?.cwd,
+ stdio: 'pipe',
+ env: envWithoutTest,
+ });Most possible culprit are these lines: https://github.com/h3js/srvx/blob/6ca26768ef4214513d34997f3346e6fcd57358b5/src/_utils.ts#L34-L36
Member
Author
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. Nice thank you!
Member
Author
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. Now it works on macOS but still fails on linux lol
Member
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. I see a good step forward. I'll check out what is happening on linux as well |
||
| }); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -126,9 +126,19 @@ | |
| opts?: { | ||
| cwd?: string; | ||
| debug?: boolean; | ||
| stripTestEnvVars?: boolean; | ||
| }, | ||
| ) { | ||
| this.taskHandle = spawn(cmd, args, { cwd: opts?.cwd, stdio: 'pipe' }); | ||
| // undefined means spawn inherits process.env by default | ||
| const env = opts?.stripTestEnvVars | ||
| ? (() => { | ||
| const e = { ...process.env }; | ||
| delete e.TEST; | ||
| return e; | ||
| })() | ||
| : undefined; | ||
|
|
||
| this.taskHandle = spawn(cmd, args, { cwd: opts?.cwd, stdio: 'pipe', env }); | ||
|
|
||
| if (opts?.debug) { | ||
| this.taskHandle.stdout?.pipe(process.stdout); | ||
|
|
@@ -207,7 +217,7 @@ | |
| resolve(false); | ||
| } else { | ||
| reject( | ||
| new Error( | ||
|
Check failure on line 220 in e2e-tests/utils/index.ts
|
||
| `Timeout waiting for output: ${output}. Got the following instead: ${outputBuffer}`, | ||
| ), | ||
| ); | ||
|
|
@@ -417,6 +427,7 @@ | |
| export async function checkIfBuilds(projectDir: string) { | ||
| const npmRunner = new ProcessRunner('npm', ['run', 'build'], { | ||
| cwd: projectDir, | ||
| stripTestEnvVars: true, | ||
| }); | ||
|
|
||
| const builtSuccessfully = await npmRunner.waitForStatusCode(0, { | ||
|
|
@@ -580,6 +591,7 @@ | |
| ) { | ||
| const npmRunner = new ProcessRunner('npm', ['run', startCommand], { | ||
| cwd: projectDir, | ||
| stripTestEnvVars: true, | ||
|
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. Dev mode missing
|
||
| }); | ||
|
|
||
| expect( | ||
|
|
||



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.
Vite plugin order differs from documented recommendation
Medium Severity
The TanStack Start documentation specifies the Vite plugin order as
tanstackStart(), nitro(), viteReact(), but herenitro()is placed afterviteReact(). Vite plugin hook execution follows array order, so this incorrect ordering could cause build or runtime failures — potentially explaining the Linux CI failures mentioned in the PR discussion.