fix(e2e): wait for HTTP readiness before resolving startServer#1675
fix(e2e): wait for HTTP readiness before resolving startServer#1675
startServer#1675Conversation
startServer
|
Warning Rate limit exceeded
Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 41 minutes and 19 seconds. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughThe changes refactor server readiness detection in the e2e testing setup. The Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (3)
src/e2e/types.ts (1)
39-45:serverStartTimeouttyped as required but not defaulted increateTestContext.The field is declared as a non-optional
number, yetcreateTestContextinsrc/e2e/context.tsdoes not assign a default for it (unlikesetupTimeout/teardownTimeout). The consumer inserver.tspapers over this withctx.options.serverStartTimeout ?? (isWindows ? 120_000 : 60_000), which means the type is effectively a lie at runtime and the platform-specific default is duplicated/owned byserver.tsrather than the central context bootstrap.Either mark the field optional, or (preferred, for consistency with sibling timeouts) initialize the default in
createTestContextand drop the fallback inserver.ts:♻️ Proposed default in
createTestContextsetupTimeout: isWindows ? 240_000 : 120_000, teardownTimeout: isWindows ? 60_000 : 30_000, + serverStartTimeout: isWindows ? 120_000 : 60_000,🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/e2e/types.ts` around lines 39 - 45, The serverStartTimeout option is declared required but not defaulted in createTestContext, causing server.ts to duplicate the platform-specific fallback; update createTestContext to initialize options.serverStartTimeout to the platform-default (use isWindows ? 120_000 : 60_000 or equivalent process.platform check) alongside setupTimeout/teardownTimeout so the context always has a value, and then remove the ad-hoc fallback in server.ts (references: serverStartTimeout, createTestContext, server.ts).src/e2e/server.ts (2)
71-78: Port-wait budget is taken from the same deadline but isn't bounded by it.
deadlineis captured beforewaitForPort, but the port wait can independently consume up toportRetries× theget-port-pleasedefault delay before the fetch loop even starts. In the worst case that can chew through (or exceed) the entireserverStartTimeout, leaving the HTTP-readiness loop with zero or one iteration and producing a confusing "Timeout … waiting for … server to become ready" error when the real failure was the port never opening.Consider either dropping the port-wait entirely (the fetch loop already retries and tolerates connection refusals via the
catch), or capping its retries to a small fixed number and letting the fetch loop own the overall budget:♻️ Suggested simplification
- const portRetries = Math.max(1, Math.ceil(timeout / 1000)) - await waitForPort(port, { retries: portRetries, host }).catch(() => {}) + // brief opportunistic wait; the fetch loop below owns the real readiness budget + await waitForPort(port, { retries: 8, host }).catch(() => {})🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/e2e/server.ts` around lines 71 - 78, The port-wait (await waitForPort(...)) can consume the entire serverStartTimeout before the HTTP readiness loop uses the shared deadline; change waitForServer so the port wait does not own the full budget: either remove the await waitForPort call entirely (the fetch loop already tolerates connection refusals) or cap its retries to a small fixed bound (e.g. Math.min(3, Math.ceil(timeout/1000))) so it only does a few quick attempts; keep the existing deadline variable (used by the fetch/readiness loop) unchanged so the HTTP loop retains the overall timeout budget.
86-100: Remove unnecessaryres.text()call in non-dev mode.The
await res.text()is always invoked even when not needed. In non-dev mode with a successful response, the body is never checked. This unnecessarily consumes the response stream; a large streaming response could keep the socket alive longer than needed. Gate the.text()call ondev:♻️ Minor refactor
const res = await globalFetch(joinURL(ctx.url!, baseURL), { signal: AbortSignal.timeout(10_000) }) - const body = await res.text() // any response means the server is accepting connections. // the dev server (`nuxi _dev`) is the one exception: it answers with // 503 or a 200 HTML placeholder containing `__NUXT_LOADING__` while the // underlying dev server is still starting up. if (dev && res.status === 503) { + await res.body?.cancel() lastError = new Error(`Server responded with ${res.status} ${res.statusText}`) } - else if (dev && body.includes('__NUXT_LOADING__')) { + else if (dev && (await res.text()).includes('__NUXT_LOADING__')) { lastError = new Error('Dev server is still starting up') } else { + await res.body?.cancel() return }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/e2e/server.ts` around lines 86 - 100, The code always calls await res.text() even when not in dev mode, which consumes the response stream unnecessarily; modify the logic in the server readiness check (the block using globalFetch/joinURL and variables res, body, dev, lastError) so that res.text() is only awaited when dev is true and you need to inspect the body for '__NUXT_LOADING__' (i.e., only compute body when dev is true), and in the non-dev successful case return immediately without reading the response body to avoid holding the response stream open.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/e2e/server.ts`:
- Around line 108-111: stopServer currently calls ctx.serverProcess.kill()
synchronously and returns immediately, so the timeout branch (where you call
await stopServer()) does not wait for the child to actually exit; change
stopServer to return a Promise that waits for the child process to emit an
exit/close event (listen on ctx.serverProcess.once('exit'/'close') and resolve)
and implement a short grace timeout after the initial kill that, if exceeded,
escalates to a forceful kill (SIGKILL or equivalent) then waits for the exit;
ensure any listeners are cleaned up and that stopServer rejects or resolves only
once the process has actually terminated.
---
Nitpick comments:
In `@src/e2e/server.ts`:
- Around line 71-78: The port-wait (await waitForPort(...)) can consume the
entire serverStartTimeout before the HTTP readiness loop uses the shared
deadline; change waitForServer so the port wait does not own the full budget:
either remove the await waitForPort call entirely (the fetch loop already
tolerates connection refusals) or cap its retries to a small fixed bound (e.g.
Math.min(3, Math.ceil(timeout/1000))) so it only does a few quick attempts; keep
the existing deadline variable (used by the fetch/readiness loop) unchanged so
the HTTP loop retains the overall timeout budget.
- Around line 86-100: The code always calls await res.text() even when not in
dev mode, which consumes the response stream unnecessarily; modify the logic in
the server readiness check (the block using globalFetch/joinURL and variables
res, body, dev, lastError) so that res.text() is only awaited when dev is true
and you need to inspect the body for '__NUXT_LOADING__' (i.e., only compute body
when dev is true), and in the non-dev successful case return immediately without
reading the response body to avoid holding the response stream open.
In `@src/e2e/types.ts`:
- Around line 39-45: The serverStartTimeout option is declared required but not
defaulted in createTestContext, causing server.ts to duplicate the
platform-specific fallback; update createTestContext to initialize
options.serverStartTimeout to the platform-default (use isWindows ? 120_000 :
60_000 or equivalent process.platform check) alongside
setupTimeout/teardownTimeout so the context always has a value, and then remove
the ad-hoc fallback in server.ts (references: serverStartTimeout,
createTestContext, server.ts).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 6e2e6f25-df84-46e6-a5c7-ce6e272829e4
📒 Files selected for processing (2)
src/e2e/server.tssrc/e2e/types.ts
commit: |
this adds configurability for starting the server + avoids orphaned processes.
additionally, we don't just wait for port to become available, but perform a fetch request to make sure it's accepting connections