Skip to content

Conversation

@schiller-manuel
Copy link
Contributor

@schiller-manuel schiller-manuel commented Jan 24, 2026

Summary by CodeRabbit

  • Tests
    • Simplified CSS module test assertions by removing retry-based checks across React, Solid, and Vue test suites
    • Tests now use direct, immediate assertions for style verification instead of wrapped retry patterns
    • Added server readiness validation before running tests
    • Streamlined test setup initialization flow with pre-optimization routines
    • Removed dependency optimization warmup from individual tests

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 24, 2026

📝 Walkthrough

Walkthrough

The PR consolidates Vite dev server warmup logic by removing per-test warmup blocks from three framework test suites (React, Solid, Vue CSS modules) and centralizing pre-optimization into shared global setup files with dedicated waitForServer and preOptimizeDevServer utilities.

Changes

Cohort / File(s) Summary
CSS Module Test Specs
e2e/react-start/css-modules/tests/css.spec.ts, e2e/solid-start/css-modules/tests/css.spec.ts, e2e/vue-start/css-modules/tests/css.spec.ts
Removed warmup beforeAll blocks that triggered Vite dependency optimization via real browser contexts. Replaced retry-wrapped assertions (toPass with 10s timeout) around style and visibility checks with direct, synchronous assertions. Simplified URL matching logic while retaining straightforward waitForURL calls.
Global Setup Helpers
e2e/react-start/css-modules/tests/setup/global.setup.ts, e2e/solid-start/css-modules/tests/setup/global.setup.ts, e2e/vue-start/css-modules/tests/setup/global.setup.ts
Added waitForServer(url) helper to poll dev server availability (30s timeout). Added preOptimizeDevServer(baseURL) helper that launches headless browser, navigates multiple routes, waits for elements and network idle, ensures URL stability via polling. Extended setup() to conditionally invoke pre-optimization when MODE === 'dev', compute dynamic baseURL from port and basepath, and validate server readiness before tests.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

Poem

🐰 Warmup logic hops away,
From specs to setup—a cleaner way!
Browser preheats with steady polls,
No more retries—stability rolls.
Tests now dance without the fuss,
Shared helpers do the work for us!

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'chore: stabilize tests' directly reflects the main objective of the pull request, which adds pre-optimization and server stability mechanisms across multiple e2e test suites.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Comment @coderabbitai help to get the list of available commands and usage tips.

@nx-cloud
Copy link

nx-cloud bot commented Jan 24, 2026

View your CI Pipeline Execution ↗ for commit 385277c

Command Status Duration Result
nx affected --targets=test:eslint,test:unit,tes... ✅ Succeeded 1m 53s View ↗
nx run-many --target=build --exclude=examples/*... ✅ Succeeded 1m 45s View ↗

☁️ Nx Cloud last updated this comment at 2026-01-24 17:24:46 UTC

@pkg-pr-new
Copy link

pkg-pr-new bot commented Jan 24, 2026

More templates

@tanstack/arktype-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/arktype-adapter@6492

@tanstack/eslint-plugin-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/eslint-plugin-router@6492

@tanstack/history

npm i https://pkg.pr.new/TanStack/router/@tanstack/history@6492

@tanstack/nitro-v2-vite-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/nitro-v2-vite-plugin@6492

@tanstack/react-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router@6492

@tanstack/react-router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router-devtools@6492

@tanstack/react-router-ssr-query

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router-ssr-query@6492

@tanstack/react-start

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start@6492

@tanstack/react-start-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-client@6492

@tanstack/react-start-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-server@6492

@tanstack/router-cli

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-cli@6492

@tanstack/router-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-core@6492

@tanstack/router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-devtools@6492

@tanstack/router-devtools-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-devtools-core@6492

@tanstack/router-generator

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-generator@6492

@tanstack/router-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-plugin@6492

@tanstack/router-ssr-query-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-ssr-query-core@6492

@tanstack/router-utils

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-utils@6492

@tanstack/router-vite-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-vite-plugin@6492

@tanstack/solid-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-router@6492

@tanstack/solid-router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-router-devtools@6492

@tanstack/solid-router-ssr-query

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-router-ssr-query@6492

@tanstack/solid-start

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start@6492

@tanstack/solid-start-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-client@6492

@tanstack/solid-start-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-server@6492

@tanstack/start-client-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-client-core@6492

@tanstack/start-fn-stubs

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-fn-stubs@6492

@tanstack/start-plugin-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-plugin-core@6492

@tanstack/start-server-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-core@6492

@tanstack/start-static-server-functions

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-static-server-functions@6492

@tanstack/start-storage-context

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-storage-context@6492

@tanstack/valibot-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/valibot-adapter@6492

@tanstack/virtual-file-routes

npm i https://pkg.pr.new/TanStack/router/@tanstack/virtual-file-routes@6492

@tanstack/vue-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/vue-router@6492

@tanstack/vue-router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/vue-router-devtools@6492

@tanstack/vue-router-ssr-query

npm i https://pkg.pr.new/TanStack/router/@tanstack/vue-router-ssr-query@6492

@tanstack/vue-start

npm i https://pkg.pr.new/TanStack/router/@tanstack/vue-start@6492

@tanstack/vue-start-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/vue-start-client@6492

@tanstack/vue-start-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/vue-start-server@6492

@tanstack/zod-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/zod-adapter@6492

commit: 385277c

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In `@e2e/react-start/css-modules/tests/setup/global.setup.ts`:
- Around line 8-19: The waitForServer function currently only treats 2xx
responses as success and has no per-attempt timeout; update waitForServer to
create an AbortController for each fetch attempt, set a short per-attempt
timeout (e.g. 5s) that calls controller.abort(), and clear that timer after the
fetch completes; change the success condition from res.ok to accept any 2xx or
3xx status (status >= 200 && status < 400) so redirects count as a successful
server response, and ensure aborted/other fetch errors are caught and ignored so
the retry loop continues.

In `@e2e/solid-start/css-modules/tests/setup/global.setup.ts`:
- Around line 8-19: The waitForServer function can hang because fetch calls may
never resolve; modify waitForServer to create an AbortController for each
iteration, pass controller.signal into fetch(url, { redirect: 'manual', signal
}), and start a per-attempt timer (e.g., 2000–3000ms) that calls
controller.abort() when expired; ensure you clear the timer after fetch
completes and keep the existing try/catch so aborted or network errors are
ignored and the loop retries, then preserve the final timeout error behavior.

In `@e2e/vue-start/css-modules/tests/setup/global.setup.ts`:
- Around line 8-19: In waitForServer, add a per-attempt AbortController and a
short timeout (e.g., 2–5s) so each fetch call cannot hang indefinitely: for each
loop iteration create an AbortController, pass controller.signal to fetch(url, {
redirect: 'manual', signal }), set a timer to call controller.abort() after the
short interval, and clear that timer after the fetch finishes or throws; keep
the existing retry loop behavior and ensure aborted fetches are caught and
ignored as before before retrying.

Comment on lines +8 to +19
async function waitForServer(url: string) {
const start = Date.now()
while (Date.now() - start < 30_000) {
try {
const res = await fetch(url, { redirect: 'manual' })
if (res.ok) return
} catch {
// ignore
}
await new Promise((r) => setTimeout(r, 250))
}
throw new Error(`Timed out waiting for dev server at ${url}`)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

find . -type f -name "global.setup.ts" | head -20

Repository: TanStack/router

Length of output: 1451


🏁 Script executed:

cat -n ./e2e/react-start/css-modules/tests/setup/global.setup.ts

Repository: TanStack/router

Length of output: 3295


🏁 Script executed:

# Check other setup files to see if there are similar patterns
head -30 ./e2e/react-router/basic/tests/setup/global.setup.ts

Repository: TanStack/router

Length of output: 279


🏁 Script executed:

# Check if there are other implementations of waitForServer or similar patterns
rg "waitForServer|redirect.*manual" --type ts --type tsx -A 5 -B 2 | head -100

Repository: TanStack/router

Length of output: 86


🏁 Script executed:

# Search for waitForServer in the codebase
rg "waitForServer" --type ts -A 5 -B 2

Repository: TanStack/router

Length of output: 3412


🏁 Script executed:

# Let me check the TypeScript/ESLint configuration for this file
head -20 ./e2e/react-start/css-modules/tsconfig.json 2>/dev/null || echo "No tsconfig in css-modules"
cat ./tsconfig.json 2>/dev/null | head -30

Repository: TanStack/router

Length of output: 1350


🏁 Script executed:

# Check the Node.js version requirement and Playwright setup
cat package.json | grep -A 10 '"engines"' || echo "No engines specified"
cat package.json | grep -A 2 '"node"' || echo "No node version in scripts"
rg "playwright" package.json

Repository: TanStack/router

Length of output: 188


🏁 Script executed:

# Check how the dev server is started and what port/behavior it has
rg "e2eStartDummyServer|getTestServerPort" --type ts -A 3 -B 1 | head -50

Repository: TanStack/router

Length of output: 4428


🏁 Script executed:

# Check if there's any documentation or context about why redirects should be accepted
rg "redirect.*basepath|basePath|3xx|redirect.*accept" --type ts | head -30

Repository: TanStack/router

Length of output: 1858


Handle redirects and per-attempt timeouts in waitForServer.

res.ok only returns true for 2xx status codes. With redirect: 'manual', 3xx responses (including base-path redirects) cause the check to fail. Additionally, the fetch call lacks a per-attempt timeout, allowing network hangs to stall the loop. Add an abort timeout per attempt and accept 3xx responses.

Suggested fix
 async function waitForServer(url: string) {
   const start = Date.now()
   while (Date.now() - start < 30_000) {
+    const controller = new AbortController()
+    const timeout = setTimeout(() => controller.abort(), 2_000)
     try {
-      const res = await fetch(url, { redirect: 'manual' })
-      if (res.ok) return
+      const res = await fetch(url, {
+        redirect: 'manual',
+        signal: controller.signal,
+      })
+      if (res.ok || (res.status >= 300 && res.status < 400)) return
     } catch {
       // ignore
-    }
+    } finally {
+      clearTimeout(timeout)
+    }
     await new Promise((r) => setTimeout(r, 250))
   }
   throw new Error(`Timed out waiting for dev server at ${url}`)
 }
🤖 Prompt for AI Agents
In `@e2e/react-start/css-modules/tests/setup/global.setup.ts` around lines 8 - 19,
The waitForServer function currently only treats 2xx responses as success and
has no per-attempt timeout; update waitForServer to create an AbortController
for each fetch attempt, set a short per-attempt timeout (e.g. 5s) that calls
controller.abort(), and clear that timer after the fetch completes; change the
success condition from res.ok to accept any 2xx or 3xx status (status >= 200 &&
status < 400) so redirects count as a successful server response, and ensure
aborted/other fetch errors are caught and ignored so the retry loop continues.

Comment on lines +8 to +19
async function waitForServer(url: string) {
const start = Date.now()
while (Date.now() - start < 30_000) {
try {
const res = await fetch(url, { redirect: 'manual' })
if (res.ok) return
} catch {
// ignore
}
await new Promise((r) => setTimeout(r, 250))
}
throw new Error(`Timed out waiting for dev server at ${url}`)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cat -n e2e/solid-start/css-modules/tests/setup/global.setup.ts | sed -n '1,30p'

Repository: TanStack/router

Length of output: 1211


🌐 Web query:

MDN fetch API res.ok status codes 3xx redirects

💡 Result:

  • Response.ok is only true for HTTP 200–299; 3xx (redirect) status codes are not “ok” (so ok === false for a 3xx response). [1]
  • In browsers, fetch() uses redirect: "follow" by default, so if the server returns a 3xx, fetch() typically follows the redirect and resolves with the final response (often 200), where response.ok may be true. You can detect that a redirect happened with response.redirected === true (and response.url will be the final URL). [2] [3]
  • You can control redirect handling with the request’s redirect mode: "follow" (default), "error", or "manual". Setting redirect: "error" is the recommended way to disallow redirects. [3] [4]

Sources:
[1] MDN: Response.ok — status in the range 200–299 https://developer.mozilla.org/en-US/docs/Web/API/Response/ok
[2] MDN: Response.redirected (detect redirects, final response.url) https://developer.mozilla.org/en-US/docs/Web/API/Response/redirected
[3] MDN: Request.redirect (follow/error/manual; default follow) https://developer.mozilla.org/en-US/docs/Web/API/Request/redirect
[4] MDN: fetch() resolves on HTTP error statuses; check ok/status https://developer.mozilla.org/en-US/docs/Web/API/Window/fetch


Add per-attempt timeout to prevent hanging fetch calls in waitForServer.

With redirect: 'manual' in effect, a 3xx response is returned as-is and will fail the res.ok check, simply retrying rather than hanging. However, the fetch call itself can hang indefinitely if the server is unresponsive, stalling the loop. Add an abort timeout (e.g., 2–3 seconds) per fetch attempt to ensure robustness.

🛠️ Suggested fix
 async function waitForServer(url: string) {
   const start = Date.now()
   while (Date.now() - start < 30_000) {
+    const controller = new AbortController()
+    const timeout = setTimeout(() => controller.abort(), 2_000)
     try {
-      const res = await fetch(url, { redirect: 'manual' })
+      const res = await fetch(url, {
+        redirect: 'manual',
+        signal: controller.signal,
+      })
       if (res.ok) return
     } catch {
       // ignore
+    } finally {
+      clearTimeout(timeout)
     }
     await new Promise((r) => setTimeout(r, 250))
   }
   throw new Error(`Timed out waiting for dev server at ${url}`)
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
async function waitForServer(url: string) {
const start = Date.now()
while (Date.now() - start < 30_000) {
try {
const res = await fetch(url, { redirect: 'manual' })
if (res.ok) return
} catch {
// ignore
}
await new Promise((r) => setTimeout(r, 250))
}
throw new Error(`Timed out waiting for dev server at ${url}`)
async function waitForServer(url: string) {
const start = Date.now()
while (Date.now() - start < 30_000) {
const controller = new AbortController()
const timeout = setTimeout(() => controller.abort(), 2_000)
try {
const res = await fetch(url, {
redirect: 'manual',
signal: controller.signal,
})
if (res.ok) return
} catch {
// ignore
} finally {
clearTimeout(timeout)
}
await new Promise((r) => setTimeout(r, 250))
}
throw new Error(`Timed out waiting for dev server at ${url}`)
}
🤖 Prompt for AI Agents
In `@e2e/solid-start/css-modules/tests/setup/global.setup.ts` around lines 8 - 19,
The waitForServer function can hang because fetch calls may never resolve;
modify waitForServer to create an AbortController for each iteration, pass
controller.signal into fetch(url, { redirect: 'manual', signal }), and start a
per-attempt timer (e.g., 2000–3000ms) that calls controller.abort() when
expired; ensure you clear the timer after fetch completes and keep the existing
try/catch so aborted or network errors are ignored and the loop retries, then
preserve the final timeout error behavior.

Comment on lines +8 to +19
async function waitForServer(url: string) {
const start = Date.now()
while (Date.now() - start < 30_000) {
try {
const res = await fetch(url, { redirect: 'manual' })
if (res.ok) return
} catch {
// ignore
}
await new Promise((r) => setTimeout(r, 250))
}
throw new Error(`Timed out waiting for dev server at ${url}`)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's check the actual file and its contents
cat -n e2e/vue-start/css-modules/tests/setup/global.setup.ts

Repository: TanStack/router

Length of output: 2727


🏁 Script executed:

# Also check if there are TypeScript errors or configuration requirements
if [ -f e2e/vue-start/css-modules/tests/setup/tsconfig.json ]; then
  cat e2e/vue-start/css-modules/tests/setup/tsconfig.json
fi

if [ -f e2e/vue-start/css-modules/tsconfig.json ]; then
  cat e2e/vue-start/css-modules/tsconfig.json
fi

if [ -f tsconfig.json ]; then
  head -50 tsconfig.json
fi

Repository: TanStack/router

Length of output: 1415


🏁 Script executed:

# Search for usages of waitForServer to understand the context
rg "waitForServer" --type ts --type tsx -B 2 -A 2

Repository: TanStack/router

Length of output: 86


🏁 Script executed:

# Search for waitForServer usage without tsx type
rg "waitForServer" -B 2 -A 2

Repository: TanStack/router

Length of output: 2632


🏁 Script executed:

# Check if there are any comments or documentation about server startup
rg "dev server|localhost|startup" e2e/vue-start/css-modules/tests/setup/ -A 2 -B 2

Repository: TanStack/router

Length of output: 856


🏁 Script executed:

# Check the e2eStartDummyServer to understand what server is being waited for
rg "e2eStartDummyServer" --type ts -B 3 -A 3

Repository: TanStack/router

Length of output: 43381


🏁 Script executed:

# Check the dummy server implementation to see what status it returns
cat -n e2e/e2e-utils/src/localDummyServer.ts | head -100

Repository: TanStack/router

Length of output: 3567


🏁 Script executed:

# Check for any 3xx redirect scenarios in the setup files
rg "basePath|redirect|301|302|3[0-9]{2}" e2e/*/css-modules/tests/setup/

Repository: TanStack/router

Length of output: 631


🏁 Script executed:

# Check if react-start has custom basepath
cat -n e2e/react-start/css-modules/tests/setup/global.setup.ts | head -30

Repository: TanStack/router

Length of output: 1211


Add per-attempt timeout to prevent hanging requests in waitForServer.

Without an AbortController, a stalled socket connection on any individual fetch attempt can hang indefinitely between retries, causing test setup delays. Add a short abort timeout per attempt to ensure each fetch times out quickly if the server is unresponsive.

🛠️ Suggested fix
 async function waitForServer(url: string) {
   const start = Date.now()
   while (Date.now() - start < 30_000) {
+    const controller = new AbortController()
+    const timeout = setTimeout(() => controller.abort(), 2_000)
     try {
-      const res = await fetch(url, { redirect: 'manual' })
-      if (res.ok) return
+      const res = await fetch(url, {
+        redirect: 'manual',
+        signal: controller.signal,
+      })
+      if (res.ok) return
     } catch {
       // ignore
+    } finally {
+      clearTimeout(timeout)
     }
     await new Promise((r) => setTimeout(r, 250))
   }
   throw new Error(`Timed out waiting for dev server at ${url}`)
 }
🤖 Prompt for AI Agents
In `@e2e/vue-start/css-modules/tests/setup/global.setup.ts` around lines 8 - 19,
In waitForServer, add a per-attempt AbortController and a short timeout (e.g.,
2–5s) so each fetch call cannot hang indefinitely: for each loop iteration
create an AbortController, pass controller.signal to fetch(url, { redirect:
'manual', signal }), set a timer to call controller.abort() after the short
interval, and clear that timer after the fetch finishes or throws; keep the
existing retry loop behavior and ensure aborted fetches are caught and ignored
as before before retrying.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants